python属性访问优先级
1 属性访问优先级为
1 __getattribute__(), 入口
2 数据描述符
3 实例对象的字典 obj.__dict__ (若与描述符同对象名,会被覆盖)
4 类的字典 Class.__dict__
5 非数据描述符
6 父类的字典
7 __getattr__()
2 调用流程
假设我们有个 类A ,其中 a是A的实例
当调用 a.x 时候属性访问顺序如下:
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