动态python函数创建覆盖函数def

时间:2014-03-18 18:32:50

标签: python

我正在尝试在类中动态创建与模块中的函数名称相关联的函数。新功能必须能够调用模块中的原始功能。但是,在下面的示例代码中,似乎可能存在内存/唯一性问题,其中创建的函数被覆盖。我想知道如何解决这个问题。

我有一个文件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_inputcreate_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

2 个答案:

答案 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)