我是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,但是 pickle 的x仍然像一个一样。我很困惑 :)

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

最佳答案

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



因此,这告诉我们, 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)

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

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

09-10 06:05
查看更多