gpt4 book ai didi

python - python copy.deepcopy时的递归错误

转载 作者:太空宇宙 更新时间:2023-11-03 11:42:21 25 4
gpt4 key购买 nike

我在 python 中遇到了问题。

我有一个自定义类 __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()

当我执行此操作时

a = ChoiceNumToName((
(1, "running"),
(2, "stopped"),
))
b = copy.deepcopy(a)

它引发 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

但谁能告诉我为什么?

最佳答案

TLDR:你的 __getattr__choice_data 之前调用已被添加到实例字典中,这导致它无休止地递归。解决该问题的更好方法是立即为以 __ 开头的任何属性引发 AttributeError捕捉任何其他特殊或内部属性。

发生这种情况是因为复制对象时 __init__方法未被调用。相反,创建了一个新的空对象。这个新对象有一个空的 __dict__ . Python 的 pickle 协议(protocol)(也用于复制模块)有一个钩子(Hook) __setstate__允许自定义应用状态(通常只是 __dict__ 的内容,但是,例如,如果提供 __getstate__,它可以是任何对象)。查看该 Hook 是否存在 hasattr(newobj, '__setstate__')被称为 which,因为没有任何 __setstate__在 MRO 或 __dict__ 中导致你的__getattr__被称为。你的__getattr__然后尝试访问 self.choice_data但是,正如我们之前提到的 __dict__目前是空的。这会导致 __getattr__再次调用方法以获取 choice_data启动无限递归的属性。

特殊套管__setstate__通过提早退出查找 __setstate__ 来阻止递归被触发.当失败时,默认的复制机制生效,初始化新对象的 __dict__。从国家。我心目中只有特殊外壳__setstate__不是最好的解决方案。我认为最好立即为任何特殊或内部属性引发 AttributeError,即以 __ 开头的那些,因为这可以防止其他奇怪情况的发生。另一种可能性是避免在 __getattr__ 中使用属性查找。通过写作 self.__dict__['choice_data']object.__getattribute__(self, 'choice_data') .您还可以确保 choice_data将通过实现 __new__ 出现并将其分配给那里的对象。

关于python - python copy.deepcopy时的递归错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47299243/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com