与python中的getattribute和setattribute混淆

新手上路,请多包涵

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

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 ( _自我_, _名字_)

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

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

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

任何人都可以给我举个例子吗?

原文由 user196264097 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 350
2 个回答

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

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

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

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

在这个类中, 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)

并且,演示了正在运行的类:

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'

原文由 Blckknght 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

原文由 Torxed 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题