如果我使用派生类,我可以“选择本地对象”吗?

新手上路,请多包涵

pickle 参考 指出 可以腌制的对象集相当有限。事实上,我有一个函数返回一个动态生成的类,我发现我不能 pickle 那个类的实例:

 >>> import pickle
>>> def f():
...     class A: pass
...     return A
...
>>> LocalA = f()
>>> la = LocalA()
>>> with open('testing.pickle', 'wb') as f:
...     pickle.dump(la, f, pickle.HIGHEST_PROTOCOL)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: Can't pickle local object 'f.<locals>.A'

这样的对象对于 pickle 来说太复杂了。好的。现在,神奇的是,如果我尝试 pickle 一个类似的对象,但它是派生类的,它就起作用了!

 >>> class DerivedA(LocalA): pass
...
>>> da = DerivedA()
>>> with open('testing.pickle', 'wb') as f:
...     pickle.dump(da, f, pickle.HIGHEST_PROTOCOL)
...
>>>

这里发生了什么事?如果这很容易,为什么 pickle 使用此解决方法来实现 dump 允许“本地对象”被腌制的方法?

原文由 fonini 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 457
2 个回答

我认为您没有仔细阅读 您引用的参考资料。该参考文献还明确指出只有以下对象是可腌制的:

  • 在模块顶层定义的函数(使用 def,而不是 >lambda)
  • 在模块顶层定义的内置函数
  • 模块顶层定义的

你的榜样

>>> def f():
...     class A: pass
...     return A

没有在模块的顶层定义类,它在 f() 范围 内定义了一个类。 pickle 适用于 _全局类_,不适用于本地类。这会自动使 pickleable 测试失败。

DerivedA 是一个全局类,所以一切都很好。

至于为什么只有顶级(对你来说是全局的)类和函数不能被腌制,参考文献也回答了这个问题(大胆的我的):

请注意,函数(内置和用户定义的)是通过 “完全限定”名称引用 而不是值来腌制的。这意味着只有函数名称以及定义该函数的模块的名称被 pickled 。 函数的代码及其任何函数属性都没有被 pickled 。因此,定义模块在 unpickling 环境中必须是可导入的,并且模块必须包含命名对象,否则将引发异常。

类似地,类通过命名引用进行 pickle,因此适用于 unpickling 环境中的相同限制。

所以你有它。 pickle 仅通过名称引用序列化对象,而不是通过对象中包含的原始指令。这是因为 pickle's 工作是序列化 _对象层次结构_,没有别的。

原文由 Akshat Mahajan 发布,翻译遵循 CC BY-SA 4.0 许可协议

我不同意,你可以腌制两者。您只需要使用更好的序列化程序,例如 dilldill (默认情况下)通过保存类定义而不是通过引用进行酸洗来腌制类,所以它不会让你的第一个案例失败。如果愿意,您甚至可以使用 dill 获取源代码。

 >>> import dill as pickle
>>> def f():
...   class A: pass
...   return A
...
>>> localA = f()
>>> la = localA()
>>>
>>> _la = pickle.dumps(la)
>>> la_ = pickle.loads(_la)
>>>
>>> class DerivedA(localA): pass
...
>>> da = DerivedA()
>>> _da = pickle.dumps(da)
>>> da_ = pickle.loads(_da)
>>>
>>> print(pickle.source.getsource(la_.__class__))
  class A: pass

>>>

原文由 Mike McKerns 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题