2017-05-31 59 views
2

據我所知,裝飾器是一個函數,它接受另一個函數作爲參數,對它執行一些操作然後返回它。Python中的裝飾器@staticmethod如何擺脫實例對象?

說到decorator @staticmethod,裝飾器究竟做了什麼來消除默認傳遞的實例對象?

+1

查看位於底部某處的Python實現:https://docs.python.org/3/howto/descriptor.html#static-methods-and-class-methods – vaultah

回答

4

staticmethod裝飾工返回一個staticmethod對象。該對象實現了descriptor protocol,與功能一樣。

這是幹什麼的不是它將實例拋棄,而是將staticmethod.__get__完全忽略綁定,只是返回未改變的函數對象。對於常規函數,function.__get__將通過返回方法對象(然後跟蹤實例和函數以在調用時組合它們)來綁定。

可以通過手動調用描述符協議重現此:

>>> class Demo: 
...  def regular(self): 
...   pass 
...  @staticmethod 
...  def static(): 
...   pass 
... 
>>> Demo.__dict__['regular'] # bypass __getattribute__ 
<function Demo.regular at 0x108515268> 
>>> Demo.__dict__['static'] # bypass __getattribute__ 
<staticmethod object at 0x1084d4f60> 
>>> Demo.__dict__['regular'].__get__(Demo()) # descriptor protocol, pass in an instance 
<bound method Demo.regular of <__main__.Demo object at 0x1084e2668>> 
>>> Demo.__dict__['static'].__get__(Demo()) # descriptor protocol, pass in an instance 
<function Demo.static at 0x1085152f0> 

通過經由Demo.__dict__訪問Demo類的屬性,我們繞過描述符協議通常由__getattribute__方法執行。如您所見,對於常規方法,函數返回對象,但對於static,則會找到staticmethod對象。

調用.__get__(Demo())來調用描述符協議,然後分別產生一個方法對象和未改變的函數對象。這正是直接訪問同一個名字上的一個實例產生:

>>> Demo().regular 
<bound method Demo.regular of <__main__.Demo object at 0x1084dde10>> 
>>> Demo().static 
<function Demo.static at 0x1085152f0> 

需要注意的是相同的協議也是classmethod對象傳遞type(instance)而不是實例作爲第一個參數的原因,也是爲什麼property對象在訪問時調用底層函數。