Python 为什么在_getattribute__中存在无限递归循环风险?
请参阅现有问题的第二个顶部答案:,其中包括某人建议的代码:Python 为什么在_getattribute__中存在无限递归循环风险?,python,Python,请参阅现有问题的第二个顶部答案:,其中包括某人建议的代码: class Count(object): def __init__(self, mymin, mymax): self.mymin = mymin self.mymax = mymax self.current = None def __getattr__(self, item): self.__dict__[item] = 0 retur
class Count(object):
def __init__(self, mymin, mymax):
self.mymin = mymin
self.mymax = mymax
self.current = None
def __getattr__(self, item):
self.__dict__[item] = 0
return 0
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return super(Count, self).__getattribute__(item)
obj1 = Count(1, 10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
我的问题是:
当我运行代码时,它并没有进入无限递归深度(以超过最大递归深度结束)。为什么?而且,如果我将代码super(Count,self)。\uuuuu getattribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。又为什么
请用详细的通话过程解释原因 我将尝试通过将self.\uu dict\uuu[item]
分为两部分来简化它:
class Count(object):
def __getattr__(self, item):
print('__getattr__:', item)
d = self.__dict__
print('resolved __dict__')
d[item] = 0
return 0
def __getattribute__(self, item):
print('__getattribute__:', item)
if item.startswith('cur'):
raise AttributeError
return super(Count, self).__getattribute__(item)
obj1 = Count()
print(obj1.current)
输出是
__getattribute__: current
__getattr__: current
__getattribute__: __dict__
resolved __dict__
0
现在,如果我们将super(Count,self)
替换为不正确的结构super(object,self)
,则不会打印消息。这是因为\uuuuu getattribute\uuuuuuuuuuuuuuuuu
还将屏蔽对\uuuuuuuuuu dict\uuuuuuuuuuuu
的访问。但是,super
对象将指向不存在的object
的基类,因此我们的\uuuu getattribute\uuuu
函数将始终抛出AttributeError
现在,在\uuuu getattribute\uuuu
失败后,\uuuuu getattr\uuuuu
正在为其进行尝试。。。好的,它不只是将\uuuuuu dict\uuuuuu
解析为某个值,而是尝试将其作为一个属性来获取,最后再次调用\uuuu getattribute\uuuuu
。因此我们得到了
....
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
Traceback (most recent call last):
File "getattribute.py", line 15, in <module>
print(obj1.current)
File "getattribute.py", line 4, in __getattr__
d = self.__dict__
File "getattribute.py", line 4, in __getattr__
d = self.__dict__
File "getattribute.py", line 4, in __getattr__
d = self.__dict__
[Previous line repeated 328 more times]
File "getattribute.py", line 8, in __getattribute__
print('__getattribute__: ', item)
RecursionError: maximum recursion depth exceeded while calling a Python object
当然,这样的代码是不正确的——尝试访问任何其他属性都会失败。某种程度上是相关的:不相关的,但在属性查找中更新对象的状态并最终创建新属性是一个非常糟糕的主意(除非您只在受保护的属性中缓存一些值,但这里不是这种情况)“当我运行代码时,它没有运行到无限递归”=>为什么它应该运行?”@Brunodesshuilliers我将行“return super(Count,self)。\uuuuuu getattribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu你永远不应该写super(object,self)
。这永远都不可能是正确的。object
上面没有任何东西。为什么getattribute会屏蔽对dict的访问?我试过你的代码,我以为代码永远不会到达print语句,但它会到达“d=self.\uuuuuuu dict\uu”。我看到你在解释中添加了,我的问题完全解决了,谢谢!似乎“object”没有名为dict的属性,而任何其他类继承了它。当我使用super(Count,self)时,self。dict可以访问,因为dict是类Count的属性。我理解正确吗?还有,你所说的dict是什么意思“尝试访问任何其他属性都会失败”
class Count(object):
def __getattr__(self, item):
setattr(self, item, 0)
return 0
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return super(object, self).__getattribute__(item)
obj1 = Count()
print(obj1.current)