Python 避免uu getattribute中的无限循环__
方法Python 避免uu getattribute中的无限循环__,python,python-3.x,Python,Python 3.x,方法\uuuu getattribute\uuuu需要仔细编写,以避免无限循环。例如: class A: def __init__(self): self.x = 100 def __getattribute__(self, x): return self.x >>> a = A() >>> a.x # infinite looop RuntimeError: maximum recursion dep
\uuuu getattribute\uuuu
需要仔细编写,以避免无限循环。例如:
class A:
def __init__(self):
self.x = 100
def __getattribute__(self, x):
return self.x
>>> a = A()
>>> a.x # infinite looop
RuntimeError: maximum recursion depth exceeded while calling a Python object
class B:
def __init__(self):
self.x = 100
def __getattribute__(self, x):
return self.__dict__[x]
>>> b = B()
>>> b.x # infinite looop
RuntimeError: maximum recursion depth exceeded while calling a Python object
因此,我们需要以这种方式编写方法:
class C:
def __init__(self):
self.x = 100
def __getattribute__(self, x):
# 1. error
# AttributeError: type object 'object' has no attribute '__getattr__'
# return object.__getattr__(self, x)
# 2. works
return object.__getattribute__(self, x)
# 3. works too
# return super().__getattribute__(x)
我的问题是为什么object.\uuuu getattribute\uuu
方法有效?object
从哪里获取\uuuu getattribute\uuuu
方法?如果对象
没有任何\uuuu getattribute\uuuu
,那么我们只是在类C
上调用相同的方法,但是通过超类调用。为什么,那么通过超类调用该方法不会导致无限循环?执行此操作时:
return object.__getattribute__(self, x)
return self.x
您正在调用一个特定的函数——在对象类中定义的函数,而不是在中定义的函数,因此不存在递归
执行此操作时:
return object.__getattribute__(self, x)
return self.x
你让python选择调用哪个函数,它从A调用这个函数,你有一个无限递归。你似乎觉得你的
\uuuu getattribute\uuuu
实现只是一个钩子,如果你提供它,python会调用它,否则,解释器将直接执行其正常功能
这是不对的。当python在实例上查找属性时,\uuu getattribute\uuu
是所有属性访问的主要条目,而object
提供默认实现。因此,您的实现将覆盖原始实现,如果您的实现没有提供返回属性的替代方法,那么它将失败。您不能在该方法中使用属性访问,因为对实例(self
)的所有属性访问都是通过类型(self)进行的
解决此问题的最佳方法是再次调用重写的原始文件。这就是super(C,self).\uu getattribute\uuu(attr)
的作用;您正在请求类解析中的下一个类为您处理属性访问
或者,您可以直接调用unbound对象。此方法的C实现是属性访问的最后一站(它可以直接访问\uuuuu dict\uuuu
,因此不受相同限制)
请注意,super()
返回一个代理对象,该对象将查找下一步在方法解析有序基类中可以找到的任何方法。如果不存在这样的方法,它将因属性错误而失败。它永远不会调用原始方法。因此Foo.bar()
查找super(Foo,self).bar
将是基类实现或属性错误,而不是Foo.bar
本身。这样写(C继承自对象):
现在您明白了为什么object.\uuuuGetAttribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但即使我没有,我仍然想知道为什么会这样的全部细节。好吧,要么你必须拦截所有属性访问,要么你不:-)@MartijnPieters——我同意。我的主要困惑是为什么从对象
调用相同的方法不会导致无限递归。为什么说“对象没有任何\uu getattribute\uuu
”<代码>a=对象();dir(a)
您将看到它被列出……在对象
类上没有定义这样的函数。如果在那里定义了一个函数,那么对象
也将定义\uuu getattr\uuu
(正如#1错误所示,它没有定义)。那么,为什么object只定义\uuuu getattribute\uuuu
方法呢?@greengit:为什么不呢?当我访问对象时,我看到
。\uuuuu getattribute\uuuu
。所以你是说对象
只定义\uu getattribte\uuuuu
,而不是\uu getattr\uuuuuu
?据我所知,object
类对所有这些方法的实现都是不可操作的。如果我在某个地方出错,请纠正我。@greengit:Nope,object.\uu getattribute\uuu
是对象属性访问的主要访问点。当您在子类上定义它时,您正在重写它,并且为了再次获得正常的行为,您需要调用被重写的实现。“我以为对象没有op实现”?到底为什么。。。?如果根对象对特殊方法的实现没有ops,那么事情怎么办?当您编写自己的时,您将覆盖什么?如果基本方法不做任何事情,这些重写将如何访问基本功能?这根本没有道理。