酸洗和取消酸洗动态加载的模块

2024-10-02 08:28:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我用以下方式创建一个对象(我知道这很可怕,不要问为什么,这是必要的):

with tempfile.NamedTemporaryFile(suffix='.py') as temp:
    temp.write(code.encode('utf-8'))
    import importlib.util
    spec = importlib.util.spec_from_file_location('a_temp_module', temp.name)
    temp_module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(temp_module)
    special_snowflake_object = temp_module.SpecialSnowflake()

现在SpecialSnowflake类实现了两种保存和加载方法,它们基本上只是pickle和unpickle它:

def save(self, file_path: str):
    with open(file_path, 'w') as fp:
        pickle.dump(self, fp)

@staticmethod
def load(file_path: str):
    with open(file_path, 'r') as fp:
        return pickle.load(fp)

但是,在调用save时,我得到了错误:

_pickle.PicklingError: Can't pickle <class 'a_temp_module.SpecialSnowflake'>: import of module 'a_temp_module' failed

这是相当奇怪的,因为我不知道你可以携带从调用实例化的对象,而不携带类定义本身,但显然,这就是这里发生的事情

我假设加载和保存可以通过以下方式完成:

with tempfile.NamedTemporaryFile(suffix='.py') as temp:
    temp.write(code.encode('utf-8'))
    import importlib.util
    spec = importlib.util.spec_from_file_location('a_temp_module', temp.name)
    temp_module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(temp_module)
    special_snowflake_object_1.save(path_to_pickle)
    special_snowflake_object_2 = temp_module.SpecialSnowflake.load(path_to_pickle)

但是我更希望save是可调用的,而不必重新加载模块,我想对于load,没有其他选择。我目前的想法是,我可以通过将模块的加载隐藏在save函数中,并将代码作为对象的属性进行传递来实现这一点。。。但我希望有一个更优雅的解决方案


Tags: pathfromsaveaswithutilloadimportlib
1条回答
网友
1楼 · 发布于 2024-10-02 08:28:16

pickle模块docs引用:

pickle can save and restore class instances transparently, however the class definition must be importable and live in the same module as when the object was stored.

pickle无法pickle a_temp_module.SpecialSnowflake的实例,因为存储在a_temp_module变量中的模块对象实际上没有使用import语句导入到全局上下文中

正如@martineau在注释中所述,pickle模块实际上并不在pickle文件中存储类定义。类定义必须可从同一模块导入

再次从pickle{a2}引用:

The following types can be pickled:

...

  • classes that are defined at the top level of a module

SpecialSnowflake类的定义也没有在__main__环境(或示例中的代码所在的任何其他环境)的顶层定义,因此您不能在该环境中pickle和unpickleSpecialSnowflake实例

相关问题 更多 >

    热门问题