[英]Python - function as class attribute becomes a bound method
我注意到,如果我在創建該類的實例時定義了一個與函數相等的類屬性,則該屬性將成為綁定方法。 有人可以向我解釋這種行為的原因嗎?
In [9]: def func():
...: pass
...:
In [10]: class A(object):
....: f = func
....:
In [11]: a = A()
In [12]: a.f
Out[12]: <bound method A.func of <__main__.A object at 0x104add190>>
In [13]: a.f()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-13-19134f1ad9a8> in <module>()
----> 1 a.f()
global a.f = <bound method A.func of <__main__.A object at 0x104add190>>
TypeError: func() takes no arguments (1 given)
您為屬性Af
(類A
的屬性f
)分配了一個函數。 屬性Af
被定義為類的一部分。 它是一個函數,因此默認情況下它是該類的實例方法。
創建類A
的實例(名為a
)會導致該實例具有屬性f
,您可以通過名稱af
訪問該屬性。 這是一個綁定方法(因為它綁定到對象a
; 這里a
進一步的解釋)。
每個實例方法在調用時都會自動接收實例作為其第一個參數(通常命名為self
)。 其他類型的方法也是可能的: - 請參閱類方法和靜態方法。
出於這個原因,錯誤說func
沒有參數(因為它被定義為def func():
)但收到了 1 ( self
)。
要做你想做的事,你應該告訴 python 你正在使用 靜態方法
def func():
pass
class A(object):
f = staticmethod(func)
Python不是基於消息的 OO 系統1 。 相反,類似於 JavaScript,屬性被解析為一等函數,然后被調用; 正如發現的那樣,這種行為在機制上略有不同。
在 Python 中,要求方法至少有一個參數,通常稱為self
,當它作為方法調用時將自動提供關聯的實例。
此外(也許是問題的關鍵),Python 在建立實例成員綁定時不區分使用def f..
或f = some_func()
; 可以說這與類之外的行為相匹配。
在示例中,將函數分配給實例“使其期望被視為實例方法”。 它是完全相同的 - 無參數 - 在兩種情況下調用的函數; 只有此類的未來使用才是相關的。
現在,與 JavaScript 不同,Python 通過綁定方法的概念來處理方法和對象關聯 - 解析為方法的函數總是“綁定”的。
af
返回綁定方法的行為 - 將自動將綁定對象作為self
提供給第一個參數的函數 - 獨立於函數的源完成。 在這種情況下,這意味着無參數函數在“綁定”時不能使用,因為它不接受self
參數。
作為示范,下面將用同樣的方法失敗,因為該源底層方法不符合接受實例作為參數的最低要求:
g = a.f
g()
在這種情況下,調用g()
等效於調用func(a)
。
1相比之下,Java、C#、Ruby 和 SmallTalk 是基於消息的 OO 系統 - 在這些系統中,對象被告知通過“名稱”調用方法,而不是將方法(或函數)解析為可以調用的值.
聚會有點晚了,但另一個可行的解決方案是將函數存儲為字典,這是類的一個屬性。
# Some arbitrary function
def f(x):
return x
# A class, which will wrap the function as a dictionary object, which is a class attr
class Test:
def __init__(self,f):
self.f = {'f':f}
def func(self,x):
return self.f['f'](x)
# Now let's test the Test object
t = Test(f=f)
t.func(3)
>>>
3
這種方法比公認的答案更冗長,但是,它沒有涉及靜態方法、裝飾器或其他高級主題。 因此,如果您被另一種首選方法嚇倒,這將在緊要關頭起作用。
編輯:如果您希望它足夠強大以處理關鍵字參數:
class Test:
def __init__(self,f):
self.f = {'f':f}
def func(self,p):
return self.f['f'](**p)
def f(**p):
return p['x'] * p['y']
t = Test(f=f)
t.func({'x':2,'y':3})
>>>
6
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.