##基礎知識:## Python Class 對象或類型經過內置成員 dict 來存儲成員信息。
還能夠經過重載 getattr 和 setattr 來攔截對成員的訪問,須要注意的是 getattr 只有在訪問不存在的成員時纔會被調用。
若是類型繼承自 object,咱們可使用 getattribute 來攔截全部(包括不存在的成員)的獲取操做html
dict 返回類的屬性字典, 會調用__getattrbute__
若是有一個類A;
a = A()
a.dict 和 A.__dict__會有所不一樣, a__dict__中沒有方法,而 A.dict 有方法。
因此可見 類方法是類的屬性被全部對像共享。python
python的對象能夠動態加屬性,例如 a.ss=3, 這時a.__dict__就會有ss的key, 而A.__dict__ 不會有這個key,從而引伸出類屬性和對象屬性(這裏不作過多解釋)。
這裏要問一個問題了:
對象的__dict__中沒有方法, 那對象是怎麼調用方法的呢?
在這裏就引伸出Descriptor個東西:git
class RevealAccess(object): def __init__(self, initval=None, name='var'): self.val = initval self.name = name def __get__(self, obj, objtype): print 'Retrieving', self.name return self.val def __set__(self, obj, val): print 'Updating' , self.name self.val = val
在類中定義__get__和__set__方法的,成爲descriptor
它是用來作什麼的呢。。。。。
再寫一個類:github
class MyClass(object): x = RevealAccess(10, 'var "x"') def __init__(self): self.y = 5 def test(self): print 'hello world!' test = RevealAccess(test, 'var "x"') if __name__ == "__main__": m = MyClass() print m.y # 輸出 # 5 print m.x # 輸出 # Retrieving var "x" # 10 print m.test # 輸出 # Retrieving var "x" # <function test at 0x02CBE870>
哈哈, 結果看出來了吧;當對像調用x(屬性),test(方法)的時候都調用了__get__方法。 這個RevealAccess的對象就是一個descriptor。訪問屬性m.x就是調用__get__方法,設置屬性值就是調用__set__方法。還能夠有一個__delete__方法,在del m.x時被調用。函數
下一個問題:
print MyClass.dict["test"] # 輸出: <function test at 0x02C9E8F0> print m.test # 輸出: <bound method MyClass.test of <main.MyClass object at 0x02C9DB70>> 這是什麼狀況, 這倆明顯不是一個東西, 什麼狀況。
這說明test方法在類中僅僅是一個function, 他跟對象仍是不要緊。 print MyClass.dict["test"].get(m, Myclass) # 輸出: <bound method MyClass.test of <main.MyClass object at 0x02CDDB90>> 這回是一個東西了,其實,類的成員函數就是一個descriptor,在實例化對象m的時候,作了m.test = MyClass.dict["test"].get(m, Myclass) 這麼一件事,這回通了。哈哈。post
有了這個基礎: 理解一下staticmethod和classmethod這兩個decorator,staticmethod就是像RevealAccess同樣忽略第一個參數,直接返回參數。classmethod就是手動賽一個對像進去: def get(self, obj, klass=None): if klass is None: klass = type(obj) def newfunc(*args): return self.f(klass, *args) return newfunccode
dict 妙用
<!-- lang: python --> class Person: def init(self,_obj): self.name = _obj['name'] self.age = _obj['age'] self.energy = _obj['energy'] .............. class Person: def init(self, _obj): self.dict.update(_obj) 這樣就減小了不少代碼量
delattr: 當使用 p = Person(); del p.name 會調用htm
主要參考http://hbprotoss.github.io/posts/python-descriptor.html http://blog.jobbole.com/21351/對象