【问题标题】:Pickle with a specific module name具有特定模块名称的泡菜
【发布时间】:2022-02-16 09:24:34
【问题描述】:

我正在使用pickle 库来序列化一个自定义对象,我们称之为A,它在a.py 中定义。

如果我在a.py 中腌制A 类型的对象,如下所示:

import pickle

class A:
    ...

if __name__ == "__main__":
    inst = A("some param")
    with open("a.pickle", 'wb') as dumpfile:
        pickle.dump(inst, dumpfile)

如果模块 A 未明确在命名空间 __main__ 中,则从存储加载此对象时会出现问题。见this other question。这是因为pickle 知道它应该在__main__ 中查找类A,因为那是pickle.dump() 发生的地方。

现在,有两种方法可以解决这个问题:

  1. 在反序列化端处理它,
  2. 在序列化结束时处理。

对于1,有多种选择(例如,请参见上面的链接),但我想避免这些,因为我认为让“pickler”对其数据负责是有意义的.

对于2,当模块位于__main__ 命名空间下时,我们可以避免酸洗,但这似乎不太灵活。我们也可以修改A.__module__,并将其设置为模块的名称(就像here一样)。 Pickle 使用这个__module__ 变量来查找从哪里导入A 类,所以在 .dump() 工作之前设置它:

if __name__ == "__main__":
    inst = A("some param")
    A.__module__ = 'a'
    with open("a.pickle", 'wb') as dumpfile:
        pickle.dump(inst, dumpfile)

问:这是个好主意吗?似乎它依赖于实现,而不是依赖于接口。也就是说,pickle 可以决定使用另一种定位要导入的模块的方法,这种方法会失败。有没有使用pickle接口的替代方案?

【问题讨论】:

  • @JacquesGaudin 谢谢,该问题中提供的dill 可能是一个不错的选择。我不知何故错过了这个问题,无论是在早期还是在回顾这个问题时。很高兴作为指向那里的重复关闭,但也许有一些关于修改 __module__ 的见解?

标签: python pickle


【解决方案1】:

另一种解决方法是导入文件本身:

import pickle
import a

class A:
    pass

def main():
    inst = a.A()
    print(inst.__module__)
    with open("a.pickle", 'wb') as dumpfile:
        pickle.dump(inst, dumpfile)

if __name__ == "__main__":
    main()

请注意,它之所以有效,是因为 import 语句纯粹是将名称 a 分配给模块对象,当您在 a.pyimport a 时,它不会进行无限递归。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-18
    • 1970-01-01
    • 1970-01-01
    • 2019-02-23
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 1970-01-01
    相关资源
    最近更新 更多