首页 > 解决方案 > Python:Pickle 如何与 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 但腌制的 x 仍然像一个。我很困惑 :)

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

标签: pythonpython-3.xpickledefaultdict

解决方案


首先,如果您查看pickle docs,特别是:

pickle 可以透明地保存和恢复类实例,但是类定义必须是可导入的,并且与存储对象时位于同一模块中

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

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

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

sub是一个空的子文件夹
a.py包含一个示例类

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

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

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)

退出外壳。移动到sub目录并尝试加载腌制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(它在不同的目录中)。在您的情况下,python 可以加载collections.defaultdict该类,因为该模块位于PYTHONPATH. 但是,要继续使用 pickle 导入的模块,您仍然需要自己导入它们;例如,您想defaultdictscript2.py.

要了解有关模块的更多信息,请查看此处,特别是6.1.2 模块搜索路径


推荐阅读