简体   繁体   English

无法腌制 object:超出最大递归深度

[英]Cannot pickle object: maximum recursion depth exceeded

I'm trying to pickle objects that I generate in a script to process them afterwards, but I get this error:我正在尝试腌制我在脚本中生成的对象以在之后处理它们,但我收到此错误:

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

Here thisperson is relatively simple (or so I thought): a name and a dictionary containing attributes:这里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

the pickle function looks like this:泡菜 function 看起来像这样:

import 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)

This error seems to be coming from the fact that the class contains a string and a dict because if I keep attributes as an empty dict I don't get the error.这个错误似乎是因为 class 包含一个字符串和一个dict ,因为如果我将属性保留为空dict ,我就不会收到错误。

Is there another way I can pickle objects like these?还有另一种方法可以腌制这样的物体吗?

I tried increasing sys.setrecursionlimit , but that didn't help.我尝试增加sys.setrecursionlimit ,但这没有帮助。

Edit: .... i can't reproduce the error if i use a short version of the code.... go figure.编辑:....如果我使用代码的简短版本,我无法重现错误.... go 图。 @MinhNguyen something weird is that i create my attributes dict in a function (attr = get_attributes(data)), but when i create the same dict myself, i can pickle it.... @MinhNguyen 奇怪的是我在 function (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)

but if i do the following it works:但如果我执行以下操作,它会起作用:

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

Solution解决方案

Alright so after further digging, i found here that pickle doesnt mingle with dict well and will often crash.好吧,在进一步挖掘之后,我在这里发现 pickle 不能很好地与 dict 混合并且经常会崩溃。

So the workaround was that i dropped the Attribute class completely and now my Person's _attribute is a string of dict self._attributes = str(dict()) and whenever i want to add things to it, i'll do an eval(), update() and str() again.所以解决方法是我完全删除了属性 class,现在我的 Person 的 _attribute 是一个 dict self._attributes = str(dict())的字符串,每当我想向它添加东西时,我都会做一个 eval(), update() 和 str() 再次。

This seem to be working so far...到目前为止这似乎有效......

Problem问题

I've been using the concurrent.futures module, particularly the ProcessPoolExecutor class, which uses (kind of under the hood) pickle module to return values to the main process.我一直在使用concurrent.futures模块,特别是ProcessPoolExecutor class,它使用(在幕后) pickle模块将值返回到主进程。 The issue with this, is that pickle module seems to have a limit on what you can "pickle-ize" when we are talking about nested stuff.这个问题是,当我们谈论嵌套的东西时, pickle模块似乎对你可以“pickle-ize”的内容有限制。 In my case, I had a structure like the following:就我而言,我有如下结构:

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

Basically, it was a list of dictionaries, which everyone of them contained, a list of string lists.基本上,它是一个字典列表,其中每个人都包含一个字符串列表列表。 I mean, it was a relatively nested structure.我的意思是,这是一个相对嵌套的结构。 And every time i tried to get the data from the ProcessPoolExecutor's result, it raised a RecursionError: maximum recursion depth exceeded while pickling an object , due to pickle module, which can't (apparently) deal with this level of nesting.每次我尝试从ProcessPoolExecutor's结果中获取data时,它都会引发RecursionError: maximum recursion depth exceeded while pickling an object ,由于 pickle 模块,它不能(显然)处理这种级别的嵌套。

Solution解决方案

My solution was similar to the provided in the edited question.我的解决方案类似于编辑后的问题中提供的解决方案。 I "stringified" the structure before pickling it, and then undone it once I could access the data .我在 pickle 之前对结构进行了“字符串化”,然后在可以访问data时撤消了它。 Personally, I used json module, which also comes with Python Standard Library.就我个人而言,我使用了 json 模块,它还附带了 Python 标准库。

This was my "experience" dealing with the pickle module.这是我处理 pickle 模块的“经验”。

pickle is known to have a number of limitations.众所周知, pickle有许多限制。 One of them you amply described - it does not handle well dictionaries where items are created on the fly.您充分描述了其中之一 - 它不能很好地处理动态创建项目的字典。

I suggest you use dill as a direct pickle replacement.我建议你用dill作为pickle的直接替代品。 It can handle this case and many more.它可以处理这种情况以及更多情况。 Just do this:只需这样做:

import dill as pickle

and leave the rest of the code intact.并保留其余代码不变。 It should work nicely.它应该工作得很好。

Quick remark: I found that for my object, IntEnum caused this.快速评论:我发现对于我的对象, IntEnum导致了这个。 Had one instance of it, replaced it with a bunch of constants, and the exception disappeared.有一个实例,用一堆常量替换它,异常消失了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM