【问题标题】:Why are there two magic methods to access object attributes in Python?为什么有两种神奇的方法可以在 Python 中访问对象属性?
【发布时间】:2014-07-10 16:07:46
【问题描述】:

我正在研究 Python 的对象属性访问模式(Descriptor HowTo GuideData model docs)。我不能清楚地理解的是,Guido 为什么同时为对象提供__getattr____getattribute__ 方法?它们都做完全相同的事情,但调用方式不同。

对我来说,这似乎是一个糟糕的设计可以通过更糟糕的设计来修复。我的意思是,如果某些内容需要重构,则不应将其与以高或更高优先级调用的魔术方法“粘合”。

问题是 - 如果一个足够完美,为什么会有两种类似的方法?

我不是指描述符,它们是不同的。

【问题讨论】:

    标签: python object attributes accessor


    【解决方案1】:

    这两种方法有不同的目的。

    __getattribute__ 调用 all 属性访问。 __getattr__ 仅在 __getattribute__ 无法定位属性时才被 调用

    实现正确的__getattr__ 方法比实现__getattribute__ 替换要容易得多。当然,在这种情况下,您可以不使用 __getattr__,但这也会使实现常见用例变得更加困难。

    例如,在__getattr__ 中,您可以轻松访问self 上的其他、现有 属性;如果您需要self.bar 来实现动态属性,那么这样做很容易。在__getattribute__ 中,您无法通过普通属性访问访问self 上的任何内容,因为这一切都由__getattribute__ 方法处理;如果你尝试过,你最终会陷入无限递归。相反,该方法中的 all 属性访问必须使用 super(ClassName, self).__getattribute__(name) 调用。

    请注意,__getattribute__始终已实现; object.__getattribute__ 提供默认实现。仅当您需要拦截默认行为时才使用__getattribute__;说在特殊情况下需要覆盖现有属性,或者覆盖普通的descriptor behaviour。请参阅 Understanding __getattribute__ 以获取覆盖现有属性访问的示例。

    __getattr__ 用于其他所有内容;例如对象上尚不存在这些属性的动态属性。假设您提供了一个代理类,其中大多数属性访问都传递给包装的对象:

    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)
    

    这里_wrappedfoo 直接在Proxy() 上找到,但如果您尝试访问bar,则Proxy 类中不存在的属性__getattr__ 会被调用,它会转换为作为self._wrapped上的属性访问。

    【讨论】:

    • 非常感谢您的解释,但相信我,这并不容易,我还不明白。您能否提供一个可以做出这种区分的真实示例?
    • @tkoomzaaskz:我已经扩展了一点,链接到 __getattribute__ 案例的不同问题/答案。
    • @tkoomzaaskz:在大多数情况下,需要覆盖 __getattribute__ 的情况很少见。这就是 __getattr__ 存在的原因,以简化常见用例。
    猜你喜欢
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    • 2021-09-19
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    相关资源
    最近更新 更多