Python:Pickle如何与defaultdict一起使用

4

我是一名新手Python程序员,正在尝试使用Pickle,但不理解它的工作原理。

我定义了一个defaultdict,并将其写入Pickle。然后在另一个脚本中读取它,即使没有导入collections模块,它仍然像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仍然像一个defaultdict一样运行。我很困惑:)
这在Python中是如何工作的?谢谢任何信息:)

有人知道吗?提前致谢。 - Wardy
1个回答

1

首先,如果您查看pickle文档,具体如下:

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

因此,这告诉我们pickle将导入定义您正在取消拣选的对象的模块。

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

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

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

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

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


1
谢谢!非常清楚。Pickle有点神秘,但感谢您的解释 :) - Wardy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接