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.
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)
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With