Python: Pickle 如何与 defaultdict 一起工作

Python: how does Pickle work with defaultdict

我是 Python 的新手,正在玩 Pickle,不明白它是如何工作的

我定义了一个defaultdict,将它写入pickle。然后在另一个脚本中我读了它,即使没有导入集合,它仍然表现得像 defaultdict

脚本 1:

import pickle
from collections import defaultdict

x = defaultdict(list)

x['a'].append(1)
print(x)

with open('pick','wb') as f:
    pickle.dump( x, f )

脚本 2:

import pickle

with open('pick','rb') as f:
    x = pickle.load( f )

x['b'].append(2)
print(x)

y = dict()

try:
    y['b'].append(2)
    print(y)
except KeyError:
    print("Can't append to y")

运行:

$ python3 pick2.py
defaultdict(<class 'list'>, {'a': [1], 'b': [2]}) 
Can't append to y

因此,第二个脚本没有导入 defaultdict,但 pickled x 仍然像一个一样。我很困惑:)

这在 Python 中如何运作?感谢您提供任何信息:)

首先,如果你看pickle docs,具体来说:

pickle can save and restore class instances transparently, however the class definition must be importable and live in the same module as when the object was stored

所以这告诉我们的是 pickle 将导入定义您要取消腌制的对象的模块。

我们可以用一个小例子来说明这一点,考虑以下文件夹结构:

parent/
|-- a.py
|-- sub/

sub 是一个空的子文件夹
a.py举个例子class

# a.py
class ExampleClass:
    def __init__(self):
        self.var = 'This is a string'

现在在 parent 目录中启动 python 控制台:

alex@toaster:parent$ python3
>>> import pickle
>>> from a import ExampleClass
>>> x = ExampleClass()
>>> x.var
'This is a string'
>>> with open('eg.p', 'wb') as f:
...     pickle.dump(x, f)

退出shell。移动到 sub 目录并尝试加载 pickled ExampleClass 对象。

alex@toaster:sub$ python3
>>> import pickle
>>> with open('../eg.p', 'rb') as f:
...     x = pickle.load(f)
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ModuleNotFoundError: No module named 'a'

我们得到一个 ModuleNotFoundError,因为 pickle 无法从模块 a(它在不同的目录中)加载 class 定义。在您的情况下,python 可以加载 collections.defaultdict class,因为此模块位于 PYTHONPATH 上。但是,要继续使用 pickle 导入的模块,您仍然需要自己导入它们;例如,您想在 script2.py.

中创建另一个 defaultdict

要了解有关模块的更多信息,请查看 here, specifically 6.1.2 The Module Search Path