簡體   English   中英

Python:將函數作為類的方法進行調用

[英]Python: calling a function as a method of a class

讓我們從一些代碼開始:

def func(*x):
    print('func:', x)


class ABC:
    def __init__(self, f):
        self.f1 = f

    def f2(*x):
        print('f2:', x)

現在我們進行一些測試:

>>> a = ABC(func)
>>> a.f1(10)
func: (10,)
>>> a.f2(10)
f2: (<__main__.ABC object at 0xb75381cc>, 10)
>>> a.f3 = func
>>> a.f3(10)
func: (10,)
>>> a.f1
<function func at 0xb74911ec>
>>> a.f2
<bound method ABC.f2 of <__main__.ABC object at 0xb75381cc>>
>>> a.f3
<function func at 0xb74911ec>

注意func是一個普通函數,我們將其作為類的方法f1

我們可以看到f2將類實例作為第一個參數,但是f1f3不是,即使所有函數都稱為類方法。 我們還可以看到,如果我們將普通函數作為類的方法來調用,Python不會從中創建綁定方法。

那么,即使我們將f1f3作為類的方法來調用,為什么f1f3沒有傳遞給它呢? 而且,Python如何知道我們將外部函數作為方法來調用,因此它不應將實例傳遞給它。

-編輯-

好的,所以基本上我做錯的是我將函數附加在實例上,而不是附加在類對象本身上。 因此,這些功能僅成為實例屬性。 我們可以用以下方法檢查:

>>> ABC.__dict__
... contents...
>>> a.__dict__
{'f1': <function func at 0xb74911ec>, 'f3': <function func at 0xb74911ec>}

另請注意,該字典不能分配給:

>>> ABC.__dict__['f4'] = func
TypeError: 'dict_proxy' object does not support item assignment

您有點回答了自己檢查對象的問題。 在Python中,對象的行為類似於名稱空間,因此第一個屬性指向函數,第二個屬性指向方法。

這是您可以動態添加方法的方式:

from types import MethodType

def func(*x):
    print('func:', x)


class ABC:
    def __init__(self, f):
        self.f1 = MethodType(f, self, self.__class__)

    def f2(*x):
        print('f2:', x)

if __name__ == '__main__':
    a = ABC(func)
    print a.f1(10)
    print a.f2(10)
    a.f3 = MethodType(func, a, ABC)
    print a.f3(10)

請注意,它將方法綁定到您的實例,而不是基類。 為了修補 ABC類:

>>> ABC.f4 = MethodType(func, None, ABC)
>>> a.f4(1)
('func:', (<__main__.ABC instance at 0x02AA8AD0>, 1))

盡管在其他動態語言(尤其是在語言年輕的Ruby中很流行)中,Monkeypatching通常在Python界不受歡迎。

如果您使用這種強大而危險的技術,我的建議是:

  • 永遠不要覆蓋現有的類方法。 只是不。

這是因為f1f3不是類方法,它們只是對__main__定義的全局函數的引用:

In [5]: a.f1
Out[5]: <function __main__.func>

In [8]: a.f3
Out[8]: <function __main__.func>

In [9]: a.f2
Out[9]: <bound method ABC.f2 of <__main__.ABC instance at 0x8ac04ac>>

您可以執行以下操作使全局函數成為類方法:

In [16]: class ABC:
    def __init__(self,f):
        ABC.f1=f
    def f2(*x):    
        print('f2',x)
   ....:         

In [17]: a=ABC(func)

In [18]: a.f1(10)
('func:', (<__main__.ABC instance at 0x8abb7ec>, 10))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM