简体   繁体   English

为什么有两种魔术方法可以访问Python中的对象属性?

[英]Why are there two magic methods to access object attributes in Python?

I'm studying Python's object attribute access patterns ( Descriptor HowTo Guide and Data model docs ). 我正在研究Python的对象属性访问模式( 描述符方法指南数据模型docs )。 The thing I can't clearly understand is why did Guido provide both __getattr__ and __getattribute__ methods for objects? 我不清楚的是Guido为什么同时为对象提供__getattr____getattribute__方法? They both do exactly the same thing but are invoked differently. 它们都做完全相同的事情,但是调用方式不同。

For me this seems as if a badly designed class could be fixed by even worse design. 对我来说,这似乎可以通过更差的设计来修复设计不好的类。 I mean, if something needs refactoring, it should not be "glued" with magic methods being called with high or higher precedence. 我的意思是,如果某些东西需要重构,则不应以高优先级或更高优先级调用魔术方法将其“粘合”。

The question is - why are there two similar methods if one would be perfectly enough? 问题是-如果一种方法足够完美,为什么会有两种类似的方法?

I'm not referring to descriptors, which are something different. 我不是指描述符,这是有所不同的。

The two methods serve different purposes. 两种方法有不同的用途。

__getattribute__ is called for all attribute access. 所有属性访问均调用__getattribute__ __getattr__ is only called by __getattribute__ if the latter failed to locate an attribute. __getattr____getattribute__找不到属性时才被调用。

It is far easier to implement a correct __getattr__ method than it is to implement a __getattribute__ replacement. 实现正确的__getattr__方法要比实现__getattribute__替换容易得多。 Sure, you can do without __getattr__ in that scenario, but that also would make implementing the common use-case all the harder. 当然,在那种情况下,您可以不用__getattr__来做,但这也将使实现通用用例变得更加困难。

For example, in __getattr__ you can easily access other, existing attributes on self ; 例如,在__getattr__您可以轻松地访问self上的其他现有属性; if you need self.bar to fulfil a dynamic attribute, then that's easy to do so. 如果您需要self.bar来实现动态属性,那么这样做很容易。 In __getattribute__ you cannot access anything on self with normal attribute access, as that is all handled by __getattribute__ methods; __getattribute__您无法通过常规属性访问self上的任何内容,因为所有这些都由__getattribute__方法处理; you'd end up in an infinite recursion if you tried. 如果尝试,最终将导致无限递归。 Instead, all attribute access within that method has to use super(ClassName, self).__getattribute__(name) calls. 相反,该方法内的所有属性访问都必须使用super(ClassName, self).__getattribute__(name)调用。

Note that __getattribute__ is always implemented; 注意__getattribute__ 总是被实现; object.__getattribute__ provides the default implementation. object.__getattribute__提供默认的实现。 Use __getattribute__ only if you need to intercept the default behaviour; 仅在需要拦截默认行为时才使用__getattribute__ say you need to override existing attributes in special circumstances, or override the normal descriptor behaviour . 说您需要在特殊情况下覆盖现有属性,或覆盖常规描述符行为 See Understanding __getattribute__ for an example where existing attribute access is being overridden. 有关覆盖现有属性访问的示例,请参见了解__getattribute__

Use __getattr__ for everything else; 使用__getattr__进行其他操作; eg dynamic attributes where those attributes do not already exist on the object. 例如动态属性,这些属性在对象上尚不存在。 Say, you are providing a proxy class, where most attribute access is passed on to the wrapped object: 假设您要提供一个代理类,其中大多数属性访问都传递给包装的对象:

class Proxy(object):
    def __init__(self, wrapped):
        self._wrapped = wrapped

    def foo(self):
        return self._wrapped.foo() + 42

    def __getattr__(self, name):
        return getattr(self._wrapped, name)

Here _wrapped and foo are found directly on Proxy() , but if you tried to access bar , an attribute that does not exist on the Proxy class, __getattr__ is called instead which translates that as attribute access on self._wrapped . 在这里_wrappedfoo直接在Proxy()上找到,但是如果您尝试访问bar ,则该属性在Proxy类上不存在,而是调用__getattr__ ,将其转换为对self._wrapped属性访问。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM