Python:Pickle如何使用defaultdict

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

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

SCRIPT1:

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 )

SCRIPT2:

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包含一个示例类

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

现在启动父目录中的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.移动到子目录并尝试加载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(它在不同的目录中)加载类定义.在您的情况下,python可以加载collections.defaultdict类,因为此模块位于PYTHONPATH上.但是,要继续使用pickle导入的模块,您仍然需要自己导入它们;例如,您想在script2.py中创建另一个defaultdict.

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

点赞