创新路
我们一直在努力

Python属性访问

一般情况下,属性访问的默认行为是从对象的字典中获取,并当获取不到时会沿着一定的查找链进行查找。例如 a.x 的查找链就是,从 a.__dict__['x'] ,然后是 type(a).__dict__['x'] ,再通过 type(a) 的基类开始查找。

__getattr__ 方法

这个方法是当对象的属性不存在是调用。如果通过正常的机制能找到对象属性的话,不会调用 __getattr__ 方法。

class A:

    a = 1

    def __getattr__(self, item):

        print('__getattr__ call')

        return item

t = A()

print(t.a)

print(t.b)

# output

1

__getattr__ call

b

__getattribute__ 方法

这个方法会被无条件调用。不管属性存不存在。如果类中还定义了 __getattr__ ,则不会调用 __getattr__() 方法,除非在 __getattribute__ 方法中显示调用__getattr__() 或者抛出了 AttributeError 。

class A:

    a = 1

    def __getattribute__(self, item):

        print('__getattribute__ call')

        raise AttributeError

    def __getattr__(self, item):

        print('__getattr__ call')

        return item

t = A()

print(t.a)

print(t.b)

所以一般情况下,为了保留 __getattr__ 的作用,__getattribute__() 方法中一般返回父类的同名方法:

def __getattribute__(self, item):

    return object.__getattribute__(self, item)

使用基类的方法来获取属性能避免在方法中出现无限递归的情况。

__get__ 方法

这个方法比较简单说明,它与前面的关系不大。

如果一个类中定义了 __get__(), __set__() 或 __delete__() 中的任何方法。则这个类的对象称为描述符。

class Descri(object):

    def __get__(self, obj, type=None):

        print("call get")

    def __set__(self, obj, value):

        print("call set")

class A(object):

    x = Descri()

a = A()

a.__dict__['x'] = 1  # 不会调用 __get__

a.x                  # 调用 __get__

如果查找的属性是在描述符对象中,则这个描述符会覆盖上文说的属性访问机制,体现在查找链的不同,而这个行文也会因为调用的不同而稍有不一样:

如果调用是对象实例(题目中的调用方式),a.x 则转换为调用: 。type(a).__dict__['x'].__get__(a, type(a))

如果调用的是类属性, A.x 则转换为:A.__dict__['x'].__get__(None, A)

其他情况见文末参考资料的文档

__getitem__ 方法

这个调用也属于无条件调用,这点与 __getattribute__ 一致。区别在于 __getitem__ 让类实例允许 [] 运算,可以这样理解:

__getattribute__ 适用于所有 . 运算符;

__getitem__ 适用于所有 [] 运算符。

class A(object):

    a = 1

    def __getitem__(self, item):

        print('__getitem__ call')

        return item

t = A()

print(t['a'])

print(t['b'])

如果仅仅想要对象能够通过 [] 获取对象属性可以简单的:

def __getitem(self, item):

    return object.__getattribute__(self, item)

未经允许不得转载:天府数据港官方信息博客 » Python属性访问

客官点个赞呗! (0)
分享到:

评论 抢沙发

评论前必须登录!

天府云博 - 做有态度的开发&运维&设计学习分享平台!

联系我们百度云主机