我在python中遇到了一个问题。在
我有一个类whis custom__getattr__
class ChoiceNumToName(object):
def __init__(self, django_choice_tuple):
self.ods_choice_tuple = django_choice_tuple
self.choice_data = {}
self.choice_point = -1
for choice_value, choice_name in django_choice_tuple:
self.choice_data.setdefault(choice_name, choice_value)
def __getattr__(self, item):
if item in self.choice_data:
return self.choice_data[item]
else:
raise AttributeError("no attribute %s" % item)
def __str__(self):
return str(self.ods_choice_tuple)
def __iter__(self):
self.choice_point = -1
return self
def __next__(self):
self.choice_point += 1
try:
return self.ods_choice_tuple[self.choice_point]
except IndexError:
raise StopIteration()
当我执行此操作时
^{pr2}$它引起RecursionError: maximum recursion depth exceeded while calling a Python object
要解决此问题,请将__getattr__
函数改为
def __getattr__(self, item):
if item == "__setstate__":
raise AttributeError(item)
if item in self.choice_data:
return self.choice_data[item]
else:
raise AttributeError("no attribute %s" % item)
效果很好。在
我从这里知道这个解决方案 https://github.com/python-babel/flask-babel/commit/8319a7f44f4a0b97298d20ad702f7618e6bdab6a
但谁能告诉我为什么吗?在
方法}用于酸洗操作。为什么这很重要?从Python docs on copying:
__getstate__
和{通过定义一个引用自身的
__setstate__
,您已经创建了一个递归对象,因此产生了RecursionError。在TLDR:在将
choice_data
添加到实例字典之前,__getattr__
会被调用,这会导致它无休止地递归。解决这个问题的一个更好的方法是立即为任何以__
开头的属性引发AttributeError,以捕获任何其他特殊或内部属性。在发生这种情况是因为复制对象时,}。然后您的
__init__
方法没有被调用。而是创建一个新的空对象。这个新对象有一个空的__dict__
。Python的pickle协议(也用于copy模块)有一个钩子__setstate__
,它允许定制应用状态(通常只是__dict__
的内容,但是,如果提供了__getstate__
,它可以是任何对象)。为了查看这个钩子是否存在,hasattr(newobj, '__setstate__')
被调用,因为MRO和__dict__
中都没有__setstate__
,所以会调用你的{__getattr__
试图访问self.choice_data
,但是,正如我们前面提到的,__dict__
当前是空的。这将导致再次调用__getattr__
方法以获得启动无限递归的choice_data
属性。在特殊的大小写}来避免在
__setstate__
阻止了由于查找__setstate__
而提前释放而触发的递归。如果失败,复制的默认机制将生效,该机制从状态初始化新对象的__dict__
。在我看来,只有特殊的外壳并不是最好的解决方案。我认为对于任何特殊的或内部的属性,即以__
开头的属性,最好立即引发AttributeError,因为这样可以防止其他奇怪的情况发生。另一种可能是通过编写self.__dict__['choice_data']
或{__getattr__
中使用属性查找。您还可以通过实现__new__
并将其分配给那里的对象来确保choice_data
将出现。在相关问题 更多 >
编程相关推荐