【问题标题】:Cannot pickle object: maximum recursion depth exceeded无法腌制对象:超出最大递归深度
【发布时间】:2020-09-13 22:08:45
【问题描述】:

我正在尝试腌制我在脚本中生成的对象以在之后处理它们,但我收到此错误:

File "<ipython-input-2-0f716e86ecd3>", line 1, in <module>
pickle.dump(thisperson, output, pickle.HIGHEST_PROTOCOL)
RecursionError: maximum recursion depth exceeded while pickling an object

这里thisperson 比较简单(或者我是这么认为的):一个名称和一个包含属性的字典:

class Attributes:
    def __init__(self, what_attr, attr):
        self._what_attr = what_attr
        self._attributes = attr

    @property
    def what_attr(self):
        return self._what_attr
    @what_attr.setter
    def what_attr(self, new_value):
        self._what_attr = new_value

    @property
    def attributes(self):
        return self._attributes
    @attributes.setter
    def attributes(self, new_value):
        self._attributes = new_value


class Person:
    def __init__(self, watname, watage):
        self._myname = watname
        self._age = watage
        self._attributes = []

    @property
    def attributes(self):
        return self._attributes
    @attributes.setter
    def attributes(self, attributes_list):
        self._attributes = attributes_list

    @property
    def myname(self):
        return self._myname
    @myname.setter
    def myname(self, value):
        self._myname = value

    @property
    def age(self):
        return self._age
    @age.setter
    def age(self, value):
        self._age = value

pickle 函数如下所示:

进口泡菜

def save_person(person, mypath):
    import os
    if not os.path.exists(mypath):
        os.makedirs(mypath)
    my_path = mypath + str(person.myname)
    if not os.path.exists(my_path + '/'):
        os.makedirs(my_path + '/')
    with open(my_path + '.pkl', 'wb') as output:
        pickle.dump(person, output, pickle.HIGHEST_PROTOCOL)

这个错误似乎是因为该类包含一个字符串和一个dict,因为如果我将属性保留为空dict,我不会收到错误。

还有其他方法可以腌制这些对象吗?

我尝试增加sys.setrecursionlimit,但没有帮助。

编辑: ....如果我使用简短版本的代码,我将无法重现该错误 .... 去看看。 @MinhNguyen 奇怪的是我在函数中创建了我的属性字典(attr = get_attributes(data)),但是当我自己创建相同的字典时,我可以腌制它....

thisperson = Person("Kenny", 22, {})
attr = get_attributes(data)  # returns {'eyes': 'blue', 'hair': 'brown'}
this_attr = Attributes(person_name, attr)
this_person.attributes.append(this_attr)
save_person(this_person, main_folder)

Exception ignored in: 
'_pydevd_frame_eval.pydevd_frame_evaluator_win32_37_64.get_bytecode_while_frame_eval'
 RecursionError: maximum recursion depth exceeded while calling a Python object
 Process finished with exit code -1073741819 (0xC0000005)

但如果我执行以下操作,它会起作用:

 attr = {'eyes': 'blue', 'hair': 'brown'}
 this_attr = Attributes(person_name, attr)
 this_person.attributes.append(this_attr)
 save_person(this_person, main_folder)

解决方案

好吧,在进一步挖掘之后,我发现here,pickle 与 dict 不能很好地混合,并且经常会崩溃。

所以解决方法是我完全放弃了 Attribute 类,现在我的 Person 的 _attribute 是一个 dict 字符串 self._attributes = str(dict()) 并且无论何时我想给它加点东西,我会再做一个 eval()、update() 和 str()。

到目前为止,这似乎有效......

【问题讨论】:

  • 附带说明,您可能希望对属性使用单下划线,如_name_attributes,而不是双下划线。前者是表示属性是实现细节的约定,而后者是invokes name mangling
  • 我们可以得到minimal reproducible example吗?
  • 由于 pickle 抱怨超出递归深度,我认为您的字典没有引起问题。你能提供更多的源代码吗?也许您根据字典的内容实现了一些具有深度的递归函数?
  • @MinhNguyen 我编辑了我的帖子以包含更多信息。我尝试根据内存和类型检查属性字典,无论我使用我的函数还是手动创建它,它们都是相同的
  • 你为什么在这里使用@property?您的任何属性都不会从中受益——它适用于公共属性与实例变量不完全对应的情况(设置某些东西有副作用,读取值涉及计算等)。跨度>

标签: python pickle


【解决方案1】:

快速评论:我发现对于我的对象,IntEnum 导致了这种情况。有一个它的实例,用一堆常量替换它,异常就消失了。

【讨论】:

    【解决方案2】:

    问题

    我一直在使用concurrent.futures 模块,尤其是ProcessPoolExecutor 类,它使用(有点在幕后)pickle 模块将值返回给主进程。 这个问题是pickle 模块似乎对我们谈论嵌套内容时可以“腌制”的内容有限制。就我而言,我的结构如下:

    data = [
        {
            "string_list": [
                ["a1", "a2", ..., "an"],
                ["b1", "b2", ..., "bn"],
                ...
                ["n1", "n2", ..., "nn"],
            ]
        },
        {
            "string_list": [
                ["a1", "a2", ..., "an"],
                ["b1", "b2", ..., "bn"],
                ...
                ["n1", "n2", ..., "nn"],
            ]
        },
    
    

    基本上,它是一个每个人都包含的字典列表,一个字符串列表的列表。我的意思是,它是一个相对嵌套的结构。每次我尝试从ProcessPoolExecutor's 结果中获取data 时,它都会引发RecursionError: maximum recursion depth exceeded while pickling an object,因为pickle 模块(显然)无法处理这种级别的嵌套。

    解决方案

    我的解决方案类似于已编辑问题中提供的解决方案。我在腌制之前对结构进行了“字符串化”,然后在可以访问data 时撤消它。我个人使用的是 json 模块,它也是 Python 标准库自带的。

    这是我处理泡菜模块的“经验”。

    【讨论】:

      猜你喜欢
      • 2016-05-23
      • 2013-12-01
      • 1970-01-01
      • 2017-03-24
      • 2011-12-31
      • 2017-08-09
      • 2011-03-31
      • 1970-01-01
      相关资源
      最近更新 更多