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

 

posted @ 2017-11-18 09:11  fuzzier  阅读(402)  评论(0编辑  收藏  举报