当你把东西扔到
pickle
您应该避免主模块中声明的酸洗类和函数。您的问题(部分)是因为您的程序中只有一个文件。
泡菜
是惰性的,不序列化类定义或函数定义。相反,它保存了一个如何查找类(它所在的模块及其名称)的引用。
当python直接运行脚本/文件时,它将程序作为
__main__
模块(不考虑其实际文件名)。但是,当文件被加载并且
不
主模块
import program
)然后,它的模块名基于它的名称。所以
program.py
接到电话
program
.
当您从命令行运行时,您正在执行前一个命令,并调用模块
_主__
. 因此,pickle创建对类的引用,例如
__main__.Signal
. 什么时候?
spyder
尝试加载命令它导入的pickle文件
_主__
寻找
Signal
. 但是,斯派德的
_主__
模块是用来启动的模块
斯皮德
而不是你的
程序.py
所以泡菜找不到
信号
.
您可以通过运行来检查pickle文件的内容(
-a
打印每个命令的说明)。从中您将看到您的类被引用为
_主信号
.
python -m pickletools -a file.pkl
你会看到类似的情况:
0: \x80 PROTO 3 Protocol version indicator.
2: c GLOBAL '__main__ Signal' Push a global object (module.attr) on the stack.
19: q BINPUT 0 Store the stack top into the memo. The stack is not popped.
21: ) EMPTY_TUPLE Push an empty tuple.
22: \x81 NEWOBJ Build an object instance.
23: q BINPUT 1 Store the stack top into the memo. The stack is not popped.
...
51: b BUILD Finish building an object, via __setstate__ or dict update.
52: . STOP Stop the unpickling machine.
highest protocol among opcodes = 2
解决
您可以使用多种解决方案:
-
不要序列化在您的
_主__
模块。最简单最好的解决方案。相反,将这些类移动到另一个模块,或者编写一个
main.py
用于调用程序的脚本(这两个脚本都意味着在
_主__
模块)。
-
编写自定义Derserialiser
-
编写自定义序列化程序
以下解决方案将使用名为pickle的pickle文件
out.pkl
由以下代码创建(在名为
程序.py
):
import pickle
class MyClass:
def __init__(self, name):
self.name = name
if __name__ == '__main__':
o = MyClass('test')
with open('out.pkl', 'wb') as f:
pickle.dump(o, f)
自定义反序列化程序解决方案
您可以编写一个客户反序列化程序,它知道何时遇到对
_主__
模块你真正的意思是
程序
模块。
import pickle
class MyCustomUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == "__main__":
module = "program"
return super().find_class(module, name)
with open('out.pkl', 'rb') as f:
unpickler = MyCustomUnpickler(f)
obj = unpickler.load()
print(obj)
print(obj.name)
这是加载已创建的pickle文件的最简单方法。该程序将责任推到反序列化代码上,而真正应该由序列化代码负责正确创建pickle文件。
自定义序列化解决方案
与前面的解决方案相比,您可以确保任何人都可以轻松地反序列化序列化的pickle对象,而无需了解自定义反序列化逻辑。为此,您可以使用
copyreg
通知模块
泡菜
如何反序列化各种类。所以在这里,你要做的就是告诉我
泡菜
反序列化的所有实例
_主__
类,就好像它们是
程序
课程。您需要为每个类注册一个自定义序列化程序。
import program
import pickle
import copyreg
class MyClass:
def __init__(self, name):
self.name = name
def pickle_MyClass(obj):
assert type(obj) is MyClass
return program.MyClass, (obj.name,)
copyreg.pickle(MyClass, pickle_MyClass)
if __name__ == '__main__':
o = MyClass('test')
with open('out.pkl', 'wb') as f:
pickle.dump(o, f)