在python中与getattribute和setattribute混淆

use*_*097 9 python python-2.7

我想知道如果我有这样的课

class Test(object):
    def __init__(self):
        self.a = 20
        self.b = 30

obj = Test()
Run Code Online (Sandbox Code Playgroud)

当我这样做obj.a,然后首先被称为?

__getattr__getattr或查找中__dict__['a']

与...相同 setattr

根据Python 2.7文档:

宾语.__getattr __(自我,名字)

当属性查找未在通常位置找到属性时调用(即,它不是实例属性,也不是在类树中找到自己).name是属性名称.此方法应返回(计算)属性值或引发AttributeError异常.

它说在通常的地方找不到.什么是平常的地方.我想知道什么时候被召唤

与此有什么不同 object.__getattribute__(self, name)

任何人都可以举例说明所有的使用方法

Blc*_*ght 39

这有点复杂.以下是Python请求对象属性时的检查顺序.

首先,Python将检查对象的类是否有__getattribute__方法.如果它没有定义,它将继承object.__getattribute__实现查找属性值的其他方法.

下一项检查是在对象的类中__dict__.但是,即使在那里找到了值,也可能不是属性查找的结果!如果在此处找到,则只有"数据描述符"优先.最常见的数据描述符是一个property对象,它是一个函数的包装器,每次访问一个属性时都会调用该函数.您可以使用装饰器创建属性:

class foo(object):
    @property
    def myAttr(self):
        return 2
Run Code Online (Sandbox Code Playgroud)

在这个类中,myAttr是一个数据描述符.这仅仅意味着它通过两者__get____set__方法实现描述符协议.A property是数据描述符.

如果类中没有__dict__包含所请求名称的任何内容,则object.__getattribute__搜索其基类(在MRO之后)以查看是否继承了该类.继承的数据描述符就像对象类中的一样.

如果找到了数据描述符,__get__则调用它的方法,返回值成为属性查找的值.如果找到一个不是数据描述符的对象,它会保持一段时间,但尚未返回.

接下来,__dict__检查对象自己的属性.这是找到大多数正常成员变量的地方.

如果对象__dict__没有任何东西,但是通过类(或基类)的早期搜索发现了除数据描述符之外的其他内容,则它具有下一个优先级.将简单地返回普通的类变量,但"非数据描述符"将获得更多的处理.

非数据描述符是具有__get__方法的对象,但没有__set__方法.最常见的非数据描述符类型是函数,当从对象作为非数据描述符进行访问时,它们成为绑定方法(这就是Python可以自动将对象作为第一个参数传递的方式).__get__将调用描述符的方法,它的返回值将是属性查找的结果.

最后,如果以前的检查都没有成功,__getattr__则会调用它(如果存在).

以下是一些使用稳定增加的优先级属性访问机制来覆盖其父类行为的类:

class O1(object):
    def __getattr__(self, name):
        return "__getattr__ has the lowest priority to find {}".format(name)

class O2(O1):
    var = "Class variables and non-data descriptors are low priority"
    def method(self): # functions are non-data descriptors
        return self.var

class O3(O2):
    def __init__(self):
        self.var = "instance variables have medium priority"
        self.method = lambda: self.var # doesn't recieve self as arg

class O4(O3):
    @property # this decorator makes this instancevar into a data descriptor
    def var(self):
        return "Data descriptors (such as properties) are high priority"

    @var.setter # I'll let O3's constructor set a value in __dict__
    def var(self, value):
        self.__dict__["var"]  = value # but I know it will be ignored

class O5(O4):
    def __getattribute__(self, name):
        if name in ("magic", "method", "__dict__"): # for a few names
            return super(O5, self).__getattribute__(name) # use normal access

        return "__getattribute__ has the highest priority for {}".format(name)
Run Code Online (Sandbox Code Playgroud)

并且,演示了这些课程:

O1(__getattr__):

>>> o1 = O1()
>>> o1.var
'__getattr__ has the lowest priority to find var'
Run Code Online (Sandbox Code Playgroud)

O2(类变量和非数据描述符):

>>> o2 = O2()
>>> o2.var
Class variables and non-data descriptors are low priority'
>>> o2.method
<bound method O2.method of <__main__.O2 object at 0x000000000338CD30>>
>>> o2.method()
'Class variables and non-data descriptors are low priority'
Run Code Online (Sandbox Code Playgroud)

O3(实例变量,包括本地重写的方法):

>>> o3 = O3()
>>> o3.method
<function O3.__init__.<locals>.<lambda> at 0x00000000034AAEA0>
>>> o3.method()
'instance variables have medium priority'
>>> o3.var
'instance variables have medium priority'
Run Code Online (Sandbox Code Playgroud)

O4(数据描述符,使用property装饰器):

>>> o4 = O4()
>>> o4.method()
'Data descriptors (such as properties) are high priority'
>>> o4.var
'Data descriptors (such as properties) are high priority'
>>> o4.__dict__["var"]
'instance variables have medium priority'
Run Code Online (Sandbox Code Playgroud)

O5(__getattribute__):

>>> o5 = O5()
>>> o5.method
<function O3.__init__.<locals>.<lambda> at 0x0000000003428EA0>
>>> o5.method()
'__getattribute__ has the highest priority for var'
>>> o5.__dict__["var"]
'instance variables have medium priority'
>>> o5.magic
'__getattr__ has the lowest priority to find magic'
Run Code Online (Sandbox Code Playgroud)