[英]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
將類實例作為第一個參數,但是f1
和f3
不是,即使所有函數都稱為類方法。 我們還可以看到,如果我們將普通函數作為類的方法來調用,Python不會從中創建綁定方法。
那么,即使我們將f1
或f3
作為類的方法來調用,為什么f1
或f3
沒有傳遞給它呢? 而且,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界不受歡迎。
如果您使用這種強大而危險的技術,我的建議是:
這是因為f1
和f3
不是類方法,它們只是對__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.