簡體   English   中英

Python - 作為類屬性的函數成為綁定方法

[英]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.

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