来自导入 class 与 class 的对象的 cloudpickle 在与 pickling 发生的同一模块中定义
cloudpickle of object from imported class versus class defined in the same module as where pickling occurs
我注意到 cloudpickle.dump(obj) 产生的 pickle 文件是不同的,这取决于 obj 的 class(称之为 SubClass,BaseClass 的子class)是在发生 cloudpickling 的同一模块中导入或定义。
特别是,如果导入了 BaseClass 和 SubClass,则 pickle 文件仅存储对 MyClass 模块和 class 的引用,这是通过反汇编字节码确定的。
如果 BaseClass 和 SubClass 定义在与 cloudpickling 发生的同一模块中,那么 pickle 文件似乎存储了 BaseClass 和 SubClass 的代码。
有谁知道为什么会这样?这是因为当它们在主模块中定义时,cloudpickle 将对象与它们的 classes 完全序列化了吗?
在发生 cloudpickling 的同一模块中定义的 BaseClass 和 SubClass:
import cloudpickle
import pickletools
class BaseClass:
def func(self):
print("BaseClass")
class SubClass(BaseClass):
def subfunc(self):
print("SubClass")
obj = SubClass()
with open("cloudpickle_object.pkl", "wb") as f:
cloudpickle.dump(obj, f)
with open("cloudpickle_object.pkl", "rb") as infile:
pickletools.dis(infile)
反汇编程序的输出显示 pickle 文件中的 BaseClass 和 SubClass 代码:
83: \x8c SHORT_BINUNICODE 'SubClass'
93: \x94 MEMOIZE (as 6)
94: h BINGET 2
96: ( MARK
97: h BINGET 5
99: \x8c SHORT_BINUNICODE 'BaseClass'
110: \x94 MEMOIZE (as 7)
111: h BINGET 3
113: \x8c SHORT_BINUNICODE 'object
从发生 cloudpickling 的不同模块导入的 BaseClass 和 SubClass:
import cloudpickle
import pickletools
from myclass import SubClass
obj = SubClass()
with open("cloudpickle_object.pkl", "wb") as f:
cloudpickle.dump(obj, f)
with open("cloudpickle_object.pkl", "rb") as infile:
pickletools.dis(infile)
仅引用子类的输出,没有引用基类或代码:
0: \x80 PROTO 4
2: \x95 FRAME 27
11: \x8c SHORT_BINUNICODE 'myclass'
20: \x94 MEMOIZE (as 0)
21: \x8c SHORT_BINUNICODE 'SubClass'
[...]
cloudpickle
仅序列化属于 __main__
模块一部分的对象,如其 github https://github.com/cloudpipe/cloudpickle.
中所述
因此,使用 import 的 pickle 对象自然会更小,因为这些对象预计会在 unpickling 时被导入。
有趣的是,为了让 cloudpickle 序列化一些导入的模块,已经有一些功能请求和一些工作已经完成。例如,
我注意到 cloudpickle.dump(obj) 产生的 pickle 文件是不同的,这取决于 obj 的 class(称之为 SubClass,BaseClass 的子class)是在发生 cloudpickling 的同一模块中导入或定义。
特别是,如果导入了 BaseClass 和 SubClass,则 pickle 文件仅存储对 MyClass 模块和 class 的引用,这是通过反汇编字节码确定的。
如果 BaseClass 和 SubClass 定义在与 cloudpickling 发生的同一模块中,那么 pickle 文件似乎存储了 BaseClass 和 SubClass 的代码。
有谁知道为什么会这样?这是因为当它们在主模块中定义时,cloudpickle 将对象与它们的 classes 完全序列化了吗?
在发生 cloudpickling 的同一模块中定义的 BaseClass 和 SubClass:
import cloudpickle
import pickletools
class BaseClass:
def func(self):
print("BaseClass")
class SubClass(BaseClass):
def subfunc(self):
print("SubClass")
obj = SubClass()
with open("cloudpickle_object.pkl", "wb") as f:
cloudpickle.dump(obj, f)
with open("cloudpickle_object.pkl", "rb") as infile:
pickletools.dis(infile)
反汇编程序的输出显示 pickle 文件中的 BaseClass 和 SubClass 代码:
83: \x8c SHORT_BINUNICODE 'SubClass'
93: \x94 MEMOIZE (as 6)
94: h BINGET 2
96: ( MARK
97: h BINGET 5
99: \x8c SHORT_BINUNICODE 'BaseClass'
110: \x94 MEMOIZE (as 7)
111: h BINGET 3
113: \x8c SHORT_BINUNICODE 'object
从发生 cloudpickling 的不同模块导入的 BaseClass 和 SubClass:
import cloudpickle
import pickletools
from myclass import SubClass
obj = SubClass()
with open("cloudpickle_object.pkl", "wb") as f:
cloudpickle.dump(obj, f)
with open("cloudpickle_object.pkl", "rb") as infile:
pickletools.dis(infile)
仅引用子类的输出,没有引用基类或代码:
0: \x80 PROTO 4
2: \x95 FRAME 27
11: \x8c SHORT_BINUNICODE 'myclass'
20: \x94 MEMOIZE (as 0)
21: \x8c SHORT_BINUNICODE 'SubClass'
[...]
cloudpickle
仅序列化属于 __main__
模块一部分的对象,如其 github https://github.com/cloudpipe/cloudpickle.
因此,使用 import 的 pickle 对象自然会更小,因为这些对象预计会在 unpickling 时被导入。
有趣的是,为了让 cloudpickle 序列化一些导入的模块,已经有一些功能请求和一些工作已经完成。例如,