Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

creating a partial-like object with dynamic arguments

I'm trying to create a partial function but with dynamic arguments that are stored as class attributes and changed accordingly. Something like the following code:

from functools import partial

def foo(*args, msg):
    print(msg)

class Bar:
    def __init__(self, msg):
        self.msg = msg
        self.functions = dict()
        self.functions['foo'] = partial(foo, msg=self.msg)

    def foo_method(self, *args):
        return self.functions['foo'](*args)

b =Bar('1')
b.foo_method()
b.msg = '2'
b.foo_method()

Only, of course, both statements will print '1' as the partial object fixes the arguments. The only alternative I found was changing the attribute to a property and manually changing the partial attributes with the setter:

class Bar:
    def __init__(self, msg):
        self._msg = None
        self.functions = dict()
        self.functions['foo'] = partial(foo)
        self.msg = msg

    def foo_method(self, *args):
        return self.functions['foo'](*args)

    @property
    def msg(self):
        return self._msg

    @msg.setter
    def msg(self, msg):
        self._msg = msg
        self.functions['foo'].keywords['msg'] = msg

I would like to know if there is a more "pythonic" / efficient way to do this, since I really don't need to use properties except for this workaround.

like image 833
Tarifazo Avatar asked Feb 06 '26 04:02

Tarifazo


2 Answers

You can use lambda instead of partial for deferred (or often referred to as "lazy") evaluation of the arguments, so that self.msg is not evaluated until the function is called:

class Bar:
    def __init__(self, msg):
        self.msg = msg
        self.functions = dict()
        self.functions['foo'] = lambda *args: foo(*args, msg=self.msg)

    def foo_method(self, *args):
        return self.functions['foo'](*args)
like image 116
blhsing Avatar answered Feb 07 '26 17:02

blhsing


What's wrong with just storing a reference to the passed function and constructing the call on the spot? i.e.:

class Bar:

    def __init__(self, msg):
        self.msg = msg
        self.foo = foo  # a reference to foo, not needed here but used as an example

    def foo_method(self, *args):
        return self.foo(*args, msg=self.msg)  # or just: foo(*args, msg=self.msg)
like image 40
zwer Avatar answered Feb 07 '26 16:02

zwer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!