有没有一种方法可以序列化 class 以便可以独立于其原始脚本对其进行反序列化?

Is there a way to serialize a class such that it can be unserialized independent of its original script?

或者,有没有一种方法可以从脚本中序列化并保存 class,如果脚本被删除,它仍然可以加载?

考虑同一目录中的三个 Python 脚本:

test.py

import pickle
import test_class_pickle

tc = test_class_pickle.Test()
pickle.dump(tc, open("/home/user/testclass", "wb"))

test_class_pickle.py

class Test:
    def __init__(self):
        self.var1 = "Hello!"
        self.var2 = "Goodbye!"

    def print_vars(self):
        print(self.var1, self.var2)

test_class_unpickle.py

import pickle

tc = pickle.load(open("/home/user/testclass", "rb"))
print(tc.var1, tc.var2)

当我 运行 test.py 时,它从 test_class_pickle 导入 Test class,创建它的实例,并将其保存到文件中使用 pickle。当我 运行 test_class_unpickle.py 时,它会按预期将 class 加载回内存。

但是,当我再次删除 test_class_pickle.py 和 运行 test_class_unpickle.py 时,它抛出这个异常:

Traceback (most recent call last):
  File "/home/sam/programs/python/testing/test_class_unpickle.py", line 3, in <module>
    tc = pickle.load(open("/home/sam/testclass", "rb"))
ModuleNotFoundError: No module named 'test_class_pickle'

有没有一种方法可以将 class 个实例保存到文件中而不依赖于原始脚本的持续存在?如果我不必使用 json 之类的东西就好了(这需要我获取 class 的所有属性的列表,将它们写入字典等),因为所有 classes 也在处理其他 classes,这些 classes 正在处理其他 classes,等等,并且每个 class 都有几个处理数据的函数。

这是让 dill 做到这一点的方法。 Dill 仅存储 __main__ 中定义的对象的定义,而不存储单独模块中的对象定义。以下函数在 __main__ 中重新定义了一个单独的模块,因此它们 存储在 pickle 文件中。基于这个答案 .

test.py

import dill
from pathlib import Path
import test_class_pickle


def mainify_module(module):
    import __main__  # This module.
    import importlib, inspect, sys

    code = inspect.getsource(module)
    spec = importlib.util.spec_from_loader(module.__name__, loader=None)
    module_obj = importlib.util.module_from_spec(spec)
    exec(code, __main__.__dict__)
    sys.modules[module.__name__] = module_obj  # Replace in cache.
    globals()[module.__name__] = module_obj  # Redefine.


pkl_filepath = Path('testclass.pkl')
pkl_filepath.unlink(missing_ok=True)  # Delete any existing file.

mainify_module(test_class_pickle)

tc = Test('I Am the Walrus!')
with open(pkl_filepath, 'wb') as file:
    dill.dump(tc, file)

print(f'dill pickle file {pkl_filepath.name!r} created')

test_class_pickle.py

class Test:
    def __init__(self, baz):
        self.var1 = "Hello!"
        self.var2 = "Goodbye!"
        self.foobar = baz

    def print_vars(self):
        print(self.var1, self.var2, self.foobar)

test_class_unpickle.py

import dill

pkl_filepath = 'testclass.pkl'

with open(pkl_filepath, 'rb') as file:
    tc = dill.load(file)

tc.print_vars()  # -> Hello! Goodbye! I Am the Walrus!