请参考现有问题的第二个最高答案:Difference between __getattr__
vs __getattribute__
,其中包括某人建议的代码:
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)
我的问题是:
当我运行代码时,它没有 not 运行到无限递归深度(通过超过最大递归深度结束)。为什么?而且,如果我将代码super(Count, self).__getattribute__(item)
更改为super(object, self).__getattribute__(item)
,它的确陷入了无限循环。又为什么呢?
请通过详细的呼叫流程说明原因。
答案 0 :(得分:3)
我将通过将self.__dict__[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)
,则不会打印该消息。这是因为__getattribute__
将也掩盖了对__dict__
的访问。但是super
对象将指向不存在的object
基类,因此我们的__getattribute__
函数将始终抛出AttributeError
。
现在,在__getattribute__
失败之后,正在尝试__getattr__
……好吧,它不仅仅是将__dict__
解析为某个值,而是尝试将其获取为属性-并最终再次调用__getattribute__
。这样我们得到了。
....
__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
如果您使用setattr(self, item, 0)
而不是查找self.__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)
当然,这样的代码不是正确的-尝试访问任何其他属性仍然会失败。