我可以“腌制本地对象"如果我使用派生类? [英] I can "pickle local objects" if I use a derived class?

查看:23
本文介绍了我可以“腌制本地对象"如果我使用派生类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<预><代码>>>>进口泡菜>>>定义 f():... A类:通过...返回A...>>>本地A = f()>>>la = LocalA()>>>with open('testing.pickle', 'wb') as f:... pickle.dump(la, f, pickle.HIGHEST_PROTOCOL)...回溯(最近一次调用最后一次):文件<stdin>",第 2 行,在 <module> 中AttributeError: 无法腌制本地对象 'f.<locals>.A'

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

<预><代码>>>>类 DerivedA(LocalA):通过...>>>da = DerivedA()>>>with open('testing.pickle', 'wb') as f:... pickle.dump(da, f, pickle.HIGHEST_PROTOCOL)...>>>

这里发生了什么?如果这很简单,为什么 pickle 不使用这个变通方法来实现一个允许本地对象"被pickle 的 dump 方法?

解决方案

我想你没有阅读 您引用的参考文献 仔细.该参考文献还明确指出,只有以下对象是可腌制的:

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

你的例子

<预><代码>>>>定义 f():... A类:通过...返回A

不在模块的顶层定义类,而是在f()范围内定义一个类.pickle 适用于全局类,而不是本地类.这会自动通过 pickleable 测试.

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

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

<块引用>

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

类似地,类通过命名引用进行酸洗,因此在 unpickling 环境中也适用相同的限制.

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

The pickle reference states that the set of objects which can be pickled is rather limited. Indeed, I have a function which returns a dinamically-generated class, and I found I can't pickle instances of that class:

>>> 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'

Such objects are too complicated for pickle. Ok. Now, what's magic is that, if I try to pickle a similar object, but of a derived class, it works!

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

What's happening here? If this is so easy, why doesn't pickle use this workaround to implement a dump method that allows "local objects" to be pickled?

解决方案

I think you did not read the reference you cite carefully. The reference also clearly states that only the following objects are pickleable:

  • functions defined at the top level of a module (using def, not >lambda)
  • built-in functions defined at the top level of a module
  • classes that are defined at the top level of a module

Your example

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

does not define a class at the top level of a module, it defines a class within the scope of f(). pickle works on global classes, not local classes. This automatically fails the pickleable test.

DerivedA is a global class, so all is well.

As for why only top-level (global to you) classes and functions can't be pickled, the reference answers that question as well (bold mine):

Note that functions (built-in and user-defined) are pickled by "fully qualified" name reference, not by value. This means that only the function name is pickled, along with the name of the module the function is defined in. Neither the function’s code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised.

Similarly, classes are pickled by named reference, so the same restrictions in the unpickling environment apply.

So there you have it. pickle only serialises objects by name reference, not by the raw instructions contained within the object. This is because pickle's job is to serialise object hierarchy, and nothing else.

这篇关于我可以“腌制本地对象"如果我使用派生类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆