I'm trying to set methods of a class programmatically by calling setattr
in a loop, but the reference I pass to the function that is called by this method defaults back to its last value, instead of what was passed at the time of the setattr
call. Curiously, I'm also setting the __doc__
attribute and this assignment actually works as expected:
class Foo2:
def do_this(self, pass_this: str):
print(pass_this)
class Foo:
def __init__(self):
self.reference = "ti-hihi"
self.foo2 = Foo2()
for (method_name, pass_this) in [("bar", "passed-for-bar"), ("bar2", "passed-for-bar2")]:
my_doc = f"""my_custom_docstring: {pass_this}"""
def some_func():
self.foo2.do_this(pass_this=pass_this)
some_func.__doc__ = my_doc
setattr(self, method_name, some_func)
if __name__ == '__main__':
f = Foo()
f.bar() # prints "pass-for-bar2" instead of "pass-for-bar"
f.bar.__doc__ # prints "pass-for-bar" as expected
I already tried a few things but couldn't figure it out.
Things I tried:
lambda -- my best bet, tbh
def some_func(reference):
self.foo2.do_this(pass_this=reference)
some_func.__doc__ = my_doc
setattr(self, method_name, lambda: some_func(pass_this))
deepcopy
import copy
def some_func():
self.foo2.do_this(pass_this=copy.deepcopy(pass_this))
some_func.__doc__ = my_doc
setattr(self, method_name, some_func)
another deepcopy variant which feels dangerous if I think about the place I want to put this:
import copy
def some_func():
self.foo2.do_this(pass_this=pass_this)
some_func.__doc__ = my_doc
setattr(self, method_name, copy.deepcopy(some_func))
... and a few combinations of those but I'm missing some crucial piece.
Thanks to @AndrewAllaire for this tip, using functools.partial
solved it for me
some_func = partial(self.foo2.do_this, pass_this=pass_this)