1 屬性訪問優先級爲html
1 __getattribute__(), 入口ui
2 數據描述符spa
3 實例對象的字典 obj.__dict__ (若與描述符同對象名,會被覆蓋) .net
4 類的字典 Class.__dict__ code
5 非數據描述符htm
6 父類的字典對象
7 __getattr__() blog
2 調用流程繼承
假設咱們有個 類A ,其中 a是A的實例
當調用 a.x 時候屬性訪問順序以下:ip
0 __getattribuite__ 爲入口
1 若是重載了 __getattribute__ ,則調用.
2 若是遇到 數據型 descriptor 會覆蓋 a.__dict__ 優先調用 a.__class__.__dict__ 的 數據型 descriptor
3 a.__dict__ , 實例中是不容許有 descriptor 的,因此不會遇到descriptor
4 A.__dict__ , 也即 a.__class__.__dict__ .
5 若是遇到了 非數據型descriptor ,則會在搜索父類屬性前優先調用
6 沿着繼承鏈搜索父類.搜索 a.__class__.__bases__ 中的全部 __dict__ . 若是有多重繼承且是菱形繼承的狀況,按 MRO(Method Resolution Order) 順序搜索.
7 若是以上都搜不到, 就會觸發 a.__getattr__, 則拋 AttributeError 異常.
3 實際示例
class Des(object): def __init__(self, name): # 第二步,描述符對象初始化 self.name = name print("__init__(): name = ", self.name) # 第十步 調用描述符Des的__get__方法 def __get__(self, instance, owner): print("__get__() ...") return self.name # 第六步 實例f._x = x時調用完__setter__後調用__set__ def __set__(self, instance, value): print 'im set' print value print 'set over' class Foo(object): # 第一步 建立描述符對象 # 第九步 由於 Foo._x 爲數據型描述符,因此覆蓋掉對象f._x _x = Des('wwt') temp = 'im temp' # 第四步 初始化實例f def __init__(self, x): self._x = x # 第八步 先會訪問更改後的__getattribute__方法 def __getattribute__(self, item): print 'im getattribute' return super(Foo, self).__getattribute__(item) # 第五步 實例f._x = x時調用__setattr__ def __setattr__(self, key, value): print 'im setter' return super(Foo, self).__setattr__(key, value) # 第三步 建立Foo對象f f = Foo(10) # 第七步 對象f屬性獲取 print f._x # 由於對象f._x被Foo._x的描述符覆蓋,因此返回爲 wwt
''' out: ('__init__(): name = ', 'wwt') im setter im set 10 set over im getattribute __get__() ... wwt '''
本文參考
Jimmy_Nie 的文章,地址爲 http://www.cnblogs.com/Jimmy1988/p/6808237.html
luozhaoyu 的文章, 地址 http://www.jb51.net/article/86749.htm