繁体   English   中英

如何在python类中动态定义方法?

[英]How to define methods dynamically inside a python class?

我想在我的类TestClass定义许多方法。 我想用他们的名字来称呼他们TestClass().method_1 ... TestClass().method_n

我不想间接调用它们,例如通过像TestClass().use_method('method_1', params)这样的中间方法来保持与代码的其他部分的一致性。

我想动态定义我的众多方法,但我不明白为什么这个最小的例子不起作用:

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)

输出是:

function_2
function_2
<function TestClass.__init__.<locals>._f at 0x0000022ED8F46430>
<function TestClass.__init__.<locals>._f at 0x0000022EDADCE4C0>

当我期待的时候

function_1
function_2

我试图在很多地方放一些 copy.deepcopy 但它没有帮助。

试图用一个更简单的例子缩小它的范围,我再次对结果感到惊讶:

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()

输出是2而我期待1

关于发生了什么的任何提示?

由于蒂姆·罗伯茨接受的答案,已编辑以提供解决方案

最小的例子:

class TestClass:
    def __init__(self):
        variable = 1

        def _f(captured_variable=variable):
            print(captured_variable)
            print(variable)
        
        del variable

        setattr(
            self,
            'the_method',
            _f)
        del _f
        
        variable = 2

if __name__ == '__main__':
    T = TestClass()
    T.the_method()

输出是:

1
2

关于动态定义方法的原始问题:

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(
                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)

输出是:

method_1
method_2
method_2
method_2
<function TestClass.__init__.<locals>._f at 0x000001D1CF9D6430>
<function TestClass.__init__.<locals>._f at 0x000001D1D187E4C0>

这是典型的 Python 绊脚石之一。 你得到变量的值,变量以最终值结束。

您可以通过“捕获”变量的值作为默认值来执行您想要的操作:

        for method_name in method_names:
            def _f(method=method_name):
                print(method)

为了更清楚地说明如何解决范围问题,您可以将该方法作为 lambda 函数的关键参数直接传递,一种可能性是:

class TestClass:
    def __init__(self, *methods):
        self.methods = methods

    def add_methods(self):
        for method in self.methods:
            setattr(type(self), method.__name__, lambda self, m=method: m())

def method_1(): return '1'
def method_2(): return '2'

t = TestClass(method_1, method_2)

t.add_methods()
print(t.method_1())
print(t.method_2())

输出

1
2

我修改了一些原始代码,但请注意setattr(type(self), ...) !!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM