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

标签 python

我想在我的类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

关于正在发生的事情有任何提示吗?

----- 编辑以提供解决方案,感谢 the accepted answer from Tim Roberts (感谢卡片注意到类型(self)而不是 self-----

最小示例:

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

输出是:

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

输出是:

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)

关于python - 如何在Python类中动态定义方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69668425/

相关文章:

python - 在 Django 中处理用户触发事件的正确方法是什么?

python - 从云函数在 Google Cloud Storage 中创建新的 csv 文件

python - 规范的嵌入式交互式 Python 解释器示例?

python - 如何将 str.startswith 用于多列?

python - Django : Object didn't load in HTML template

python - 如何使用 KMeans 对多维和未知数据进行聚类?

python - 找不到 zsh 命令 : conda after upgrading to Catalina and even after reinstalling Anaconda

python - 如何将 pandas 数据框中的字符串拆分为二元组,然后可以分解为新行?

python - 将 PyArrayObject 数据类型转换为 C 数组

python - 写入 Oracle : TypeError: expecting string or bytes object