【问题标题】:Can top level classes be pickled and unpickled (documentation wrong?)顶级课程可以腌制和解封(文档错误吗?)
【发布时间】:2016-03-22 16:58:40
【问题描述】:

下面链接的文档似乎说可以腌制顶级类及其实例。但根据我之前的question 的答案,这似乎不正确。在我发布的脚本中,pickle 接受类对象并写入一个文件,但这没有用。

这是我的问题:这个文档是错误的,还是有一些我不明白的更微妙的东西?另外,在这种情况下,pickle 是否应该生成某种错误消息?

https://docs.python.org/2/library/pickle.html#what-can-be-pickled-and-unpickled,

可以腌制以下几种:

  • 无、真和假
  • 整数、长整数、浮点数、复数
  • 普通和 Unicode 字符串
  • 仅包含可提取对象的元组、列表、集合和字典
  • 在模块顶层定义的函数
  • 在模块顶层定义的内置函数
  • 在模块顶层定义的类我的粗体
  • 这些类的实例,其 dict 或调用 getstate() > 的结果是可腌制的(有关详细信息,请参阅腌制协议部分)。

【问题讨论】:

  • 在我看来,文档清楚地解释了腌制课程的含义,而您的争论在于是否应该意味着腌制课程。
  • 无意争吵。我试图了解“腌制课程”的确切含义。如果你很清楚,你能发布一些东西作为答案吗?我原本以为我可以恢复定义,这样我就可以创建更多实例,但这似乎是错误的。

标签: python pickle


【解决方案1】:

创建一个在模块顶层定义的类

foo.py

class Foo(object): pass

然后运行一个单独的脚本,

script.py

import pickle
import foo


with open('/tmp/out.pkl', 'w') as f:
    pickle.dump(foo.Foo, f)

del foo

with open('/tmp/out.pkl', 'r') as f:
    cls = pickle.load(f)

print(cls)

打印

<class 'foo.Foo'>

请注意,pickle 文件out.pkl 仅包含字符串,这些字符串命名定义模块和类的名称。它不存储类的定义:

cfoo
Foo
p0
.

因此,在 unpickling 时定义模块 foo 必须包含类的定义。如果你从定义模块中删除类

del foo.Foo

然后你会得到错误

AttributeError: 'module' object has no attribute 'Foo'

【讨论】:

  • 谢谢!的确,这是我几天前在question 上的经历。所以我越来越接近理解,你能帮我理解在没有定义的情况下腌制一个类有什么用处。是否只是管理类的名称?
  • 查看@justhalf 下方answer的评论
  • @uhoh:腌制一个类本质上与存储类的名称(作为字符串)和定义模块的名称(作为字符串)相同。如果您只是将类名和模块名存储为字符串,那么您可以使用module = __import__(module_name)cls = getattr(module, class_name) 而不是酸洗。在使用多处理模块时,我倾向于只使用酸洗(隐式)——因为所有通过Queues 的对象都会被酸洗。对于长期持久性,我倾向于使用其他机制,例如JSON 或数据库,以避免版本或语言不兼容。
  • 感谢您抽出宝贵时间进一步解释。这真的很有帮助!
【解决方案2】:

完全可以在 python 中腌制一个类实例......同时还保存代码来重建类和实例的状态。如果您想在pickle 之上组合一个解决方案,或者使用基于exec 的“特洛伊木马”方法,请按照以下方法操作:

How to unpickle an object whose class exists in a different namespace (python)?

或者,如果您使用dill,那么您有一个dump 函数,它已经知道如何存储类实例、类代码和实例状态:

How to recover a pickled class and its instances

Pickle python class instance plus definition

我是dill 的作者,我创建dill 的部分原因是为了能够跨multiprocessing 传送类实例和类方法。

Can't pickle <type 'instancemethod'> when using python's multiprocessing Pool.map()

【讨论】:

  • 谢谢@Mike。问题指的是 pickle 模块及其文档。现在我看到“酸洗”一词可以更广泛地用于其他基于泡菜和类似泡菜的程序。很高兴在这里收集这些链接。
  • 明白了……请注意,我的第一个链接显示了如何完全按照 dill 所做的操作,但仅使用 pickle 模块。如果为类注册了序列化方法,那么类就可以序列化。文档是关于 pickle 的,没有使用 copyreg 的任何用户扩展。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多