与python中的getattribute和setattribute混淆 [英] Confused with getattribute and setattribute in python

查看:78
本文介绍了与python中的getattribute和setattribute混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

类测试(对象):def __init__(self):自我.a = 20自我.b = 30对象 = 测试()

当我做obj.a时,先调用哪个?

__getattr__getattr 或在 __dict__['a']

中查找

setattr

相同

根据 Python 2.7 文档:

<块引用>

object.__getattr__(self, name)

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

它说在通常的地方找不到.那平常的地方是什么.我想知道什么时候调用

还有这个 object.__getattribute__(self, name)

谁能给我举个例子

解决方案

有点复杂.如果您请求对象的属性,Python 会执行以下检查序列.

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

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

class foo(object):@财产def myAttr(self):返回 2

在这个类中,myAttr 是一个数据描述符.这只是意味着它通过同时具有 __get____set__ 方法来实现描述符协议.property 是一个数据描述符.

如果该类的 __dict__ 中没有任何具有请求名称的内容,object.__getattribute__ 会搜索其基类(遵循 MRO)以查看是否存在是继承的.继承的数据描述符就像对象类中的描述符一样工作.

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

接下来,检查对象自己的__dict__ 的属性.这是大多数普通成员变量的所在.

如果对象的 __dict__ 没有任何东西,但之前在类(或基类)中的搜索找到了数据描述符以外的东西,则它具有下一个优先级.一个普通的类变量将被简单地返回,但非数据描述符"将得到更多的处理.

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

最后,如果前面的检查都没有成功,__getattr__ 将被调用(如果存在).

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

O1 类(对象):def __getattr__(self, name):return "__getattr__ 具有最低优先级来查找 {}".format(name)O2(O1) 类:var = "类变量和非数据描述符为低优先级"def method(self): # 函数是非数据描述符返回 self.varO3(O2) 类:def __init__(self):self.var = "实例变量具有中等优先级"self.method = lambda: self.var # 不接收 self 作为 argO4(O3) 类:@property # 这个装饰器把这个 instancevar 变成了一个数据描述符定义变量(自我):返回数据描述符(如属性)是高优先级的"@var.setter # 我会让 O3 的构造函数在 __dict__ 中设置一个值def var(self, value):self.__dict__["var"] = value # 但我知道它会被忽略O5(O4)级:def __getattribute__(self, name):if name in ("magic", "method", "__dict__"): # 一些名字return super(O5, self).__getattribute__(name) # 使用普通访问return "__getattribute__ 对 {} 具有最高优先级".format(name)

并且,演示类的操作:

O1 (__getattr__):

<预><代码>>>>o1 = O1()>>>o1.var'__getattr__ 找到 var 的优先级最低'

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

<预><代码>>>>o2 = O2()>>>o2.var类变量和非数据描述符为低优先级'>>>o2.方法<0x000000000338CD30处<__main__.O2对象的绑定方法O2.method>>>>>o2.method()'类变量和非数据描述符是低优先级的'

O3(实例变量,包括一个本地覆盖的方法):

<预><代码>>>>o3 = O3()>>>o3.方法<function O3.__init__.<locals>.<lambda>在 0x00000000034AAEA0>>>>o3.method()'实例变量具有中等优先级'>>>o3.var'实例变量具有中等优先级'

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

<预><代码>>>>o4 = O4()>>>o4.method()'数据描述符(例如属性)具有高优先级'>>>o4.var'数据描述符(如属性)具有高优先级'>>>o4.__dict__["var"]'实例变量具有中等优先级'

O5(__getattribute__):

<预><代码>>>>o5 = o5()>>>o5.方法<function O3.__init__.<locals>.<lambda>在 0x0000000003428EA0>>>>o5.method()'__getattribute__ 对 var 具有最高优先级'>>>o5.__dict__["var"]'实例变量具有中等优先级'>>>o5.magic'__getattr__ 寻找魔法的优先级最低'

I want to know that if I have class like this

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

obj = Test()

When I do obj.a, then which is called first?

__getattr__ or getattr or lookup in __dict__['a']

and same with setattr

According to Python 2.7 docs:

object.__getattr__(self, name)

Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.

It says not found in usual places. what is that usual places. I want to know when it is called

also what is the diff with this object.__getattribute__(self, name)

Can anyone give me example where all are used

解决方案

It's a bit complicated. Here's the sequence of checks Python does if you request an attribute of an object.

First, Python will check if the object's class has a __getattribute__ method. If it doesn't have one defined, it will inherit object.__getattribute__ which implements the other ways of finding the attribute's values.

The next check is in the object's class's __dict__. However, even if a value is found there, it may not be the result of the attribute lookup! Only "data descriptors" will take precedence if found here. The most common data descriptor is a property object, which is a wrapper around a function that will be called each time an attribute is accessed. You can create a property with a decorator:

class foo(object):
    @property
    def myAttr(self):
        return 2

In this class, myAttr is a data descriptor. That simply means that it implements the descriptor protocol by having both __get__ and __set__ methods. A property is a data descriptor.

If the class doesn't have anything in its __dict__ with the requested name, object.__getattribute__ searches through its base classes (following the MRO) to see if one is inherited. An inherited data descriptor works just like one in the object's class.

If a data descriptor was found, it's __get__ method is called and the return value becomes the value of the attribute lookup. If an object that is not a data descriptor was found, it is held on to for a moment, but not returned just yet.

Next, the object's own __dict__ is checked for the attribute. This is where most normal member variables are found.

If the object's __dict__ didn't have anything, but the earlier search through the class (or base classes) found something other than a data descriptor, it takes next precedence. An ordinary class variable will be simply returned, but "non-data descriptors" will get a little more processing.

A non-data descriptor is an object with a __get__ method, but no __set__ method. The most common kinds of non-data descriptors are functions, which become bound methods when accessed as a non-data descriptor from an object (this is how Python can pass the object as the first argument automatically). The descriptor's __get__ method will be called and it's return value will be the result of the attribute lookup.

Finally, if none of the previous checks succeeded, __getattr__ will be called, if it exists.

Here are some classes that use steadily increasing priority attribute access mechanisms to override the behavior of their parent class:

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)

And, a demonstration of the classes in action:

O1 (__getattr__):

>>> o1 = O1()
>>> o1.var
'__getattr__ has the lowest priority to find var'

O2 (class variables and non-data descriptors):

>>> 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'

O3 (instance variables, including a locally overridden method):

>>> 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'

O4 (data descriptors, using the property decorator):

>>> 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'

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'

这篇关于与python中的getattribute和setattribute混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆