classmethod(function)
這里不過多說明這個builtin方法的具體用法,python的文檔和help函數已經給了這個方法充足的使用說明,所以我這里要說的時關於 classmethod , property之流的注解方法背后所用的技術細節,也是python中比較難以理解的一個知識點, 那就是 python中的 描述符。
從現象開始分析
class Person(object):
country = 'china'
def __init__(self, name):
self.name = name
def say(self):
print self.name
這個類開始分析,首先運行如下代碼
me = Person('younger')
Person.__dict__
me.__dict__
結果為
>>> Person.__dict__
dict_proxy({'__module__': '__main__', 'country': 'china', 'age': 20, 'say': <function say at 0x1047e0b18>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, ' __doc__': None, '__init__': <function __init__ at 0x1047e0b90>})
>>> me.__dict__
{'name': 'younger'}
我們的類和實例都具有__dict__屬性,這個字典中囊括了該對象中所有的屬性(類也是對象)。
繼續運行代碼
me.country
結果為
>>> me.country
'china'
繼續運行代碼
me.__dict__['country]
結果為
>>> me.__dict__['country']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'country'
由此可見,當我們調用實例屬性的時候,me.name和me.dict['name'] 的結果是一樣的,當調用的是類屬性的時候,就截然不同了,結果顯而易見,當我們再調用不同的屬性的時候,系統會自動做出一些判斷,但是我們現在還不知道判斷是怎么進行的,也不知道是什么時候進行的,這里還不做解答,再看一個關於類中方法調用的例子。
我們繼續運行代碼
Person.say
Person.__dict__['say']
me.say
me.__dict__['say']
運行結果為
>>> Person.say
<unbound method Person.say>
>>> Person.__dict__['say']
<function say at 0x1047e0b18>
>>> p.say
<bound method Person.say of <__main__.Person object at 0x10473a190>>
>>> p.__dict__['say']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'say'
先不管方法有沒有被綁定,先看下結果,我們再用點和__dict__訪問一個方法的時候,得到的是全然不同的結果,理論上來說應該是會得到一樣的結果,因為都是要再當前對象的__dict__ 中進行查找,為什么Person的返回會完全不同呢?而且就返回結果來說,Person.say返回的結果類型為 未綁定的instancemethod, 而 Person.__dict__['say'] 返回的是普通的function類型對象, 方法的返回和調用完全和與其的不一樣, 這就是描述符的作用。
官方對描述符的定義是:
一個描述符, 是一個對象對某個 “綁定” 方法的描述。
用自己的話來說,就是一個類中實現一些類似於 __get__, __set__, __getattr__, __getattribute__ 的方法,然后再對屬性進行各種操作的時候,這些方法將會進行類似過濾的操作,來幫助你做一些額外的工作。
拿上面的例子來說,調用一個方法有兩種情況,一種是在類中調用,另一種是實例種調用,如果是對象種調用,那么對象的 __getattribute__方法會做返回 type(obj).__dict__['func'].__get__(obj, type(obj)), 如果是類在調用,那么會被返回為 cls.__dict__['func'].__get__(None, cls), 這里___getattribute__, 起到了巨大的作用,用各種get方法進行了過濾, 所以在對方法進行操作的時候,用點和__dict__進行調回會有不同的結果,這也是描述符的作用所在。
你可以寫自己的描述符,來對屬性的讀寫進行操作。
現在我們回到staticmethod這個裝飾器方法上來
class StaticMethod(object):
"Emulate PyStaticMethod_Type() in Objects/funcobject.c
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
return self.f
上面是文檔種對這個方法的python模擬,實際上builtin種的方法都是c的方法,該裝飾器在get的時候進行自定義操作。
舉個例子
>>> class E(object):
def f(klass, x):
return klass.__name__, x
f = classmethod(f)
>>> print E.f(3)
('E', 3)
>>> print E().f(3)
('E', 3)