簡體   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