I want to define many methods in my class TestClass
.
I want to call them by their name TestClass().method_1
... TestClass().method_n
.
I do not want to call them indirectly for example through an intermediate method like TestClass().use_method('method_1', params)
to keep consistency with other parts of the code.
I want to define dynamically my numerous methods, but I do not understand why this minimal example does not work:
class TestClass:
def __init__(self):
method_names = [
'method_1',
'method_2']
for method_name in method_names:
def _f():
print(method_name)
# set the method as attribute
# (that is OK for me that it will not be
# a bound method)
setattr(
self,
method_name,
_f)
del _f
if __name__ == '__main__':
T = TestClass()
T.method_1()
T.method_2()
print(T.method_1)
print(T.method_2)
Output is:
function_2
function_2
<function TestClass.__init__.<locals>._f at 0x0000022ED8F46430>
<function TestClass.__init__.<locals>._f at 0x0000022EDADCE4C0>
while I was expecting
function_1
function_2
I tried to put some copy.deepcopy at many places but it does not help.
Trying to narrow it down with a more minimal example, I am again surprised by the result:
class TestClass:
def __init__(self):
variable = 1
def _f():
print(variable)
del variable
setattr(
self,
'the_method',
_f)
del _f
variable = 2
if __name__ == '__main__':
T = TestClass()
T.the_method()
Output is 2
while I was expecting 1
.
Any hint about what is happening?
----- Edited to give solution thanks to the accepted answer from Tim Roberts (and thanks cards for noticing the type(self) instead of self-----
Minimal example:
class TestClass:
def __init__(self):
variable = 1
def _f(captured_variable=variable):
print(captured_variable)
print(variable)
del variable
setattr(
type(self),
'the_method',
_f)
del _f
variable = 2
if __name__ == '__main__':
T = TestClass()
T.the_method()
Output is:
1
2
And original question about dynamically defined methods:
class TestClass:
def __init__(self):
method_names = [
'method_1',
'method_2']
for method_name in method_names:
def _f(captured_method=method_name):
print(captured_method)
print(method_name)
# set the method as attribute
setattr(
type(self),
method_name,
_f)
del _f
if __name__ == '__main__':
T = TestClass()
T.method_1()
T.method_2()
print(T.method_1)
print(T.method_2)
Output is:
method_1
method_2
method_2
method_2
<function TestClass.__init__.<locals>._f at 0x000001D1CF9D6430>
<function TestClass.__init__.<locals>._f at 0x000001D1D187E4C0>