我正在尝试在类中动态创建与模块中的函数名称相关联的函数。新功能必须能够调用模块中的原始功能。但是,在下面的示例代码中,似乎可能存在内存/唯一性问题,其中创建的函数被覆盖。我想知道如何解决这个问题。
我有一个文件mymod.py
,我将作为模块导入:
def exec_test0():
print "i am exec_test0"
def exec_test1():
print "i am exec_test1"
和一个文件test.py
,其中包含需要读取模块的类定义:
import mymod as mm
class MyClass():
def __init__(self):
self.l = [fn for fn in dir(mm) if fn.startswith('exec_')]
self.create_method()
def create_method(self):
# i expect this to create new methods with unique properties
# as attributes of an object of this class
for fn_exec in self.l:
# this is the function template
# that i want to call the relevant function from the
# module mymod (mm)
def method(self):
method_to_call = getattr(mm, fn_exec)
method_to_call()
# this should create a new name based on the fn_exec
# and assign method to it
name_def = fn_exec.replace('exec_', 'do_')
setattr(self.__class__, name_def, method)
if __name__ == '__main__':
my_obj = MyClass()
my_obj.do_test0()
my_obj.do_test1()
运行test.py
的输出是:
i am exec_test1
i am exec_test1
我期待:
i am exec_test0
i am exec_test1
非常感谢任何有关如何实现这一目标的帮助!
更新:下面给出了答案,但是我将在这里写一个简短的修改,并在课堂上为新函数扩展以接受输入。
create_method()
中的test.py
方法应按照以下接受的答案中的说明进行更新:
def create_method(self):
# i expect this to create new methods with unique properties
# as attributes of an object of this class
for fn_exec in self.l:
# this is the function template
# that i want to call the relevant function from the
# module mymod (mm)
# because this run at runtime, it requires a param instead
def method(self, fn=fn_exec):
method_to_call = getattr(mm, fn)
method_to_call()
# this should create a new name based on the fn_exec
# and assign method to it
name_def = fn_exec.replace('exec_', 'do_')
setattr(self.__class__, name_def, method)
此外,如果需要将参数传递给新方法,例如输入some_input
,create_method()
将更新为:
def create_method(self):
# i expect this to create new methods with unique properties
# as attributes of an object of this class
for fn_exec in self.l:
# this is the function template
# that i want to call the relevant function from the
# module mymod (mm)
# because this run at runtime, it requires a param instead
def method(self, some_input, fn=fn_exec):
method_to_call = getattr(mm, fn)
method_to_call()
print(some_input)
# this should create a new name based on the fn_exec
# and assign method to it
name_def = fn_exec.replace('exec_', 'do_')
setattr(self.__class__, name_def, method)
,主要块可能如下所示:
if __name__ == '__main__':
my_obj = MyClass()
my_obj.do_test0('a')
my_obj.do_test1('b')
将具有以下输出:
i am exec_test0
a
i am exec_test1
b
答案 0 :(得分:2)
在fn_exec
被称为之前,method
正文中的名称method
不会被评估,此时fn_exec
具有最后一个值它采用了for
循环。为了确保在method
定义时它的值,您需要使用默认参数值:
def method(self, fn=fn_exec):
method_to_call = getattr(mm, fn)
method_to_call()
定义method
后,fn
设置为等于fn_exec
的当前值,因此这是定义method_to_call
时使用的值。
答案 1 :(得分:0)
这与闭包在Python中的工作方式有关。添加如下方法:
def make_wrapper(self, method_to_call):
def method(self):
method_to_call()
并将create_method()
更改为:
def create_method(self):
for fn_exec in self.l:
method_to_call = getattr(mm, fn_exec)
method = self.make_wrapper(method_to_call)
name_def = fn_exec.replace('exec_', 'do_')
setattr(self.__class__, name_def, method)
由于您是在实例上执行此操作,我建议在实例上设置方法(并绑定到self),而不是直接在类上设置它们:
setattr(self, name_def, method.__get__(self, self.__class__))
# Instead of
setattr(self.__class__, name_def, method)