13

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

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

obj = Test()

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

__getattr__getattr或查找__dict__['a']

和一样setattr

根据Python 2.7 文档

目的。__getattr__自我姓名

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

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

这还有什么区别object.__getattribute__(self, name)

谁能给我举个例子

4

4 回答 4

45

这有点复杂。如果您请求对象的属性,这是 Python 执行的检查序列。

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

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

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

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

如果该类中没有任何__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)

并且,演示类的实际操作:

O1 ( __getattr__):

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

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'

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'

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'

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'
于 2013-02-09T11:15:50.267 回答
1
class test():
    def __init__(self):
        self.a = 1

    def __getattribute__(self, attr):
        print 'Getattribute:',attr

    def __getattr__(self, attr):
        print 'GetAttr:',attr

    def __dict__(self, attr):
        print 'Dict:',attr

    def __call__(self, args=None):
        print 'Called:',args

    def __getitem__(self, attr):
        print 'GetItem:',attr

    def __get__(self, instance, owner):
        print 'Get:',instance,owner

    def __int__(self):
        print 'Int'



x = test()
print x.a

以上都不会被调用..

[root@faparch doxid]# python -m trace --trace test_dict.py
 --- modulename: test_dict, funcname: <module>
test_dict.py(1): class test():
 --- modulename: test_dict, funcname: test
test_dict.py(1): class test():
test_dict.py(2):    def __init__(self):
test_dict.py(5):    def __getattribute__(self, attr):
test_dict.py(8):    def __getattr__(self, attr):
test_dict.py(11):   def __dict__(self, attr):
test_dict.py(14):   def __call__(self, args=None):
test_dict.py(17):   def __getitem__(self, attr):
test_dict.py(20):   def __get__(self, instance, owner):
test_dict.py(23):   def __int__(self):
test_dict.py(28): x = test()
 --- modulename: test_dict, funcname: __init__
test_dict.py(3):        self.a = 1
test_dict.py(29): print x.a
1
 --- modulename: trace, funcname: _unsettrace
trace.py(80):         sys.settrace(None)

您可能需要查看:http ://docs.python.org/2/library/numbers.html#numbers.Number 您很可能 需要实现一个嵌套类来按顺序处理数字类函数抢夺电话,例如示例中的电话。或者,至少这是一种方法..

整数值包含您必须拦截的以下函数

['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
于 2013-02-09T11:25:46.343 回答
0

命名空间字典(__dict__)首先被调用。

来自docs

类实例有一个作为字典实现的命名空间,这是搜索属性引用的第一个位置。如果在那里找不到属性,并且实例的类具有该名称的属性,则使用类属性继续搜索。如果没有找到类属性,并且对象的类有一个 __getattr__()方法,则调用该方法以满足查找。

文档object.__getattribute__

无条件调用以实现类实例的属性访问。如果该类还定义了__getattr__(),则不会调用后者,除非__getattribute__()显式调用它或引发AttributeError. 此方法应返回(计算的)属性值或引发AttributeError异常。

文档object.__getattr__(self, name)

如果属性是通过正常机制找到的,__getattr__() 则不调用。

于 2013-02-09T11:13:28.630 回答
0

文档

... 例如,obj.d 在 obj 的字典中查找 d。如果 d 定义了方法__get__(),则 d.__get__(obj)根据下面列出的优先规则调用。

...对于对象,机器在object.__getattribute__()其中转换b.xtype(b).__dict__['x'].__get__(b, type(b))。该实现通过优先链工作,该优先链赋予数据描述符优先于实例变量,实例变量优先于非数据描述符,并分配最低优先级( __getattr__()如果提供)。

也就是说,obj.a默认__getattribute__()情况下使用__dict__. __getattr__()被称为最后的手段。其余部分描述描述符,例如,property或普通方法行为。

如何d定义方法__get__()

import random 

class C(object):
    @property
    def d(self):
        return random.random()

c = C()
print(c.d)
于 2013-02-09T11:13:49.157 回答