为什么Python的defaultdict在pickle中表现得很奇怪?

问题描述 投票:0回答:2

我正在使用 PySpark,它使用 Python 的 pickle 来序列化对象。我的用例有一个嵌套的

defaultdict
数据结构,例如:

from collections import defaultdict

nested_dict = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))

腌制这个

nested
defaultdict
结构给出

PicklingError:无法在 0x1076cc9d8> 进行腌制>:__main__ 上的属性查找失败

有一个很棒的解决方法在一个SO答案中。

我一直在尝试这样做,并对它导致的一些不直观的功能/用法感到好奇。例如,

import pickle

def dd():
    def di():
        return defaultdict(int)
    return defaultdict(di)

nested = defaultdict(dd)
pickle.loads(pickle.dumps(nested))

有效,但以下无效

def nested_dd():
    def dd():
        def di():
            return defaultdict(int)
        return defaultdict(di)
    return defaultdict(dd)

pickle.loads(pickle.dumps(nested_dd()))

它给了

AttributeError:无法腌制本地对象

nested_dd.<locals>.dd

这里发生了什么事?

python python-3.x serialization pickle defaultdict
2个回答
4
投票

虽然存在其他序列化技术,但您只能

pickle
可以通过
from … import foo
找到的函数(因为这就是unpickling函数所做的)。如果外部
defaultdict
不为空,您的“工作”示例将会失败,因为每个嵌套字典都会有一个本地函数作为 its 默认工厂。

在这种情况下,由于这些函数都没有关闭任何东西,因此您可以将它们写在顶层。


0
投票

还有另一种非常简单的解决方法可能适合您的用例,但我没有在任何答案中看到。唯一需要注意的是,如果在 pickle 之后继续扩展字典,您将丢失默认值。只需做:

pickle.dump(dict(nested_dict))
© www.soinside.com 2019 - 2024. All rights reserved.