考慮一個簡單的例子:
class C:
@staticmethod
def my_static_method():
print("static")
def my_instance_method(self):
print("self")
當我呼叫 時C().my_static_method(),python 不會傳遞Cinto的實體my_static_method,并且參考的描述符也不my_static_method期望 的實體C。
這是有道理的。
但是當我呼叫時C().my_instance_method(),python如何知道將C我正在呼叫的實體my_instance_method作為引數傳遞,而不需要我指定任何內容?
uj5u.com熱心網友回復:
正如鏈接所解釋的,函式物件是描述符!就像staticmethod物體一樣。
他們有一個回傳系結方法物件的方法__get__,它本質上只是將實體本身部分應用為第一個位置引數。考慮:
>>> def foo(self):
... return self.bar
...
>>> class Baz:
... bar = 42
...
>>> baz = Baz()
>>> bound_method = foo.__get__(baz, Baz)
>>> bound_method
<bound method foo of <__main__.Baz object at 0x7ffcd001c7f0>>
>>> method()
42
uj5u.com熱心網友回復:
通過將 @staticmethod 裝飾器添加到 my_static_method,您告訴 python 不要將 C 的呼叫實體傳遞給函式。因此,您可以將此函式稱為 C.my_static_method()。
通過呼叫 C(),您創建了一個C實體。然后您呼叫了非靜態函式 my_instance_method(),Python 愉快地將您的新 C 實體作為第一個引數傳遞。
當您呼叫 C.my_instance_method() 時會發生什么?
修辭:你會得到一個“缺少一個必需的 arg self”例外——因為 my_instance_method 僅在從實體呼叫時才有效,除非你將其裝飾為靜態。
當然,您仍然可以從實體 C().my_static_method() 呼叫靜態成員,但您沒有 self 引數,因此無法訪問該實體。
uj5u.com熱心網友回復:
這里的關鍵點是方法只是恰好是類屬性的函式。在 Python 中,真正的魔法發生在屬性查找程序中。您之前提供的鏈接解釋了每次x.y在 Python 中發生的情況。(請記住,一切都是物件;包括函式、類、模塊(它是自身type的實體)...)
這個程序就是描述符可以作業的原因。為什么我們需要明確的self;以及為什么我們可以做一些有趣的事情,比如用普通的函式呼叫語法呼叫方法(只要我們從類而不是實體中查找它),給它取別名,用functools.partial...模擬方法系結程序。
假設我們有c = C(). 當您這樣做時c.my_instance_method(暫時不介意呼叫它),Python 會查找my_instance_methodin type(c)(即,在C類中),并且還會檢查它是否是描述符,以及它是否是特定的資料描述符。函式是非資料描述符;即使在課堂之外,你也可以寫
>>> def x(spam): return spam
...
>>> x.__get__
<method-wrapper '__get__' of function object at 0x...>
由于優先級規則,只要c不直接附加同名的屬性,就會在 中找到C 并__get__使用該函式。請注意,有__get__問題的來自班級 - 但它沒有使用與x.__get__上述相同的程序。該代碼在類中查找,因為這是檢查屬性查找的地方之一;但是當c.my_instance_method重定向到時,它直接C.my_instance_method.__get__看那里- 將屬性直接附加到函式不會改變任何東西(這就是為什么被實作為類的原因)。__get__staticmethod
這__get__實作了實際的方法系結。假設我們x在類中找到了一個方法str:
>>> x.__get__('spam', str)
<bound method x of 'spam'>
>>> x.__get__('spam', str)()
'spam'
請記住,盡管所討論的函式需要三個引數,但我們將__get__本身作為方法呼叫- 所以x以相同的方式系結到它。等效且更忠實于實際程序:
>>> type(x).__get__(x, 'spam', str)
<bound method x of 'spam'>
>>> type(x).__get__(x, 'spam', str)()
'spam'
那么究竟什么是“系結方法”呢?
>>> bound = type(x).__get__(x, 'spam', str)
>>> type(bound)
<class 'method'>
>>> bound.__call__
<method-wrapper '__call__' of method object at 0x...>
>>> bound.__func__
<function x at 0x...>
>>> bound.__self__
'spam'
>>> type(bound)(x, 'eggs')
<bound method x of 'eggs'>
幾乎是你所期望的:它是一個可呼叫物件,存盤和使用原始函式和self值,并且在__call__.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/417509.html
標籤:
上一篇:將字串作為輸入并轉換字母?
