为什么Python中有两种神奇的方法来访问对象属性?

为什么Python中有两种神奇的方法来访问对象属性?,python,object,attributes,accessor,Python,Object,Attributes,Accessor,我正在研究Python的对象属性访问模式(和)。我不清楚的是,为什么Guido同时为对象提供了\uuuu getattr\uuuu和\uuu getattribute\uuuu方法?它们都做完全相同的事情,但调用方式不同 对我来说,这似乎是一个设计糟糕的类可以通过更糟糕的设计来修复。我的意思是,如果某个东西需要重构,它不应该被“粘合”在以高或更高优先级调用的神奇方法上 问题是——如果一种方法足够完美,为什么会有两种类似的方法 我指的不是描述符,它们有些不同。这两种方法有不同的用途 \uuuu g

我正在研究Python的对象属性访问模式(和)。我不清楚的是,为什么Guido同时为对象提供了
\uuuu getattr\uuuu
\uuu getattribute\uuuu
方法?它们都做完全相同的事情,但调用方式不同

对我来说,这似乎是一个设计糟糕的类可以通过更糟糕的设计来修复。我的意思是,如果某个东西需要重构,它不应该被“粘合”在以高或更高优先级调用的神奇方法上

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

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

这两种方法有不同的用途

\uuuu getattribute\uuuu
用于all属性访问<如果
\uuuuGetAttr\uuuuuuu
找不到属性,则只能由
\uuuuuuuGetAttribute\uuuuuuuuu
调用

实现正确的
\uuu getattr\uuu
方法要比实现
\uu getattribute\uuu
替换容易得多。当然,在这种情况下,您可以不使用
\uuuu getattr\uuuu
,但这也会使实现通用用例变得更加困难

例如,在
\uuu getattr\uuuu
中,您可以轻松访问
self
上的其他现有属性;如果您需要
self.bar
来实现动态属性,那么这很容易做到。在
\uuuuuu getattribute\uuuuuu
中,您不能使用正常的属性访问来访问
self
上的任何内容,因为这都是由
\uuuuuuuu getattribute\uuuuuuuu
方法处理的;如果你尝试的话,你会在一个无限的递归中结束。相反,该方法中的所有属性访问必须使用
super(ClassName,self)。\uuu getattribute\uuuu(name)
调用

请注意,
\uuu getattribute\uuu
始终是实现的<代码>对象。提供默认实现。仅当需要拦截默认行为时,才使用
\uuuuu getattribute\uuuu
;假设您需要在特殊情况下覆盖现有属性,或者覆盖普通属性。有关覆盖现有属性访问的示例,请参见

使用
\uuuu getattr\uuuu
进行其他操作;e、 g.对象上不存在这些属性的动态属性。比方说,您提供了一个代理类,其中大多数属性访问都传递给包装对象:

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)
此处可直接在
Proxy()
上找到
\u wrapped
foo
,但如果您试图访问
bar
,则
Proxy
类上不存在的属性,改为调用
\uuu getattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

\uuuu getattribute\uuuu
用于all属性访问<如果
\uuuuGetAttr\uuuuuuu
找不到属性,则只能由
\uuuuuuuGetAttribute\uuuuuuuuu
调用

实现正确的
\uuu getattr\uuu
方法要比实现
\uu getattribute\uuu
替换容易得多。当然,在这种情况下,您可以不使用
\uuuu getattr\uuuu
,但这也会使实现通用用例变得更加困难

例如,在
\uuu getattr\uuuu
中,您可以轻松访问
self
上的其他现有属性;如果您需要
self.bar
来实现动态属性,那么这很容易做到。在
\uuuuuu getattribute\uuuuuu
中,您不能使用正常的属性访问来访问
self
上的任何内容,因为这都是由
\uuuuuuuu getattribute\uuuuuuuu
方法处理的;如果你尝试的话,你会在一个无限的递归中结束。相反,该方法中的所有属性访问必须使用
super(ClassName,self)。\uuu getattribute\uuuu(name)
调用

请注意,
\uuu getattribute\uuu
始终是实现的<代码>对象。提供默认实现。仅当需要拦截默认行为时,才使用
\uuuuu getattribute\uuuu
;假设您需要在特殊情况下覆盖现有属性,或者覆盖普通属性。有关覆盖现有属性访问的示例,请参见

使用
\uuuu getattr\uuuu
进行其他操作;e、 g.对象上不存在这些属性的动态属性。比方说,您提供了一个代理类,其中大多数属性访问都传递给包装对象:

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)

此处可直接在
Proxy()
上找到
\u wrapped
foo
,但如果您试图访问
bar
,则
Proxy
类上不存在的属性,取而代之的是调用
\uuuu getattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。你能提供一个现实世界的例子来说明这种区别吗?@tkoomzaaskz:我已经扩展了一点,链接到了
\uuuuu getattribute\uuuuuu
案例的不同问题/答案。@tkoomzaaskz:需要覆盖
\uuu getattribute\uuuuuu
在大多数情况下是很少的。这就是为什么存在
\uuu getattr\uuuu
,使通用用例变得简单。我非常感谢您的解释,但相信我,这并不容易,我还不明白。你能提供一个现实世界的例子来说明这种区别吗?@tkoomzaaskz:我已经扩展了一点,链接到了
\uuuuu getattribute\uuuuuu
案例的不同问题/答案。@tkoomzaaskz:需要覆盖
\uuu getattribute\uuuuuu
在大多数情况下是很少的。这就是为什么存在
\uuuu getattr\uuuu
,以简化通用用例。