如果我使用派生类,我可以"pickle local objects"?

fon*_*ini 25 python nested pickle python-3.x

pickle参考文献指出可以酸洗的物体组是相当有限的.实际上,我有一个函数返回一个dinamically生成的类,我发现我不能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'
Run Code Online (Sandbox Code Playgroud)

这些对象太复杂了pickle.好.现在,有什么神奇的,如果我试图挑选一个类似的对象,但是派生类,它就可以了!

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

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

Aks*_*jan 34

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

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

你的榜样

>>> def f():
...     class A: pass
...     return A
Run Code Online (Sandbox Code Playgroud)

在模块的顶部电平不定义类,它定义了一个内类范围f().pickle适用于全局类,而不是本地类.这会自动使pickleable测试失败.

DerivedA 是全球一流的,所以一切都很好.

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

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

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

所以你有它.pickle仅按名称引用序列化对象,而不是通过对象中包含的原始指令.这是因为pickle's作业是序列化对象层次结构,而不是其他任何东西.


Mik*_*rns 19

我不同意,你可以腌制两者.你只需要使用更好的序列化器,比如dill. dill(默认情况下)通过保存类定义而不是通过引用进行pickle来修改类,因此它不会使第一种情况失败.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

>>> 
Run Code Online (Sandbox Code Playgroud)


haa*_*ael 7

您只能腌制在模块顶级定义的类的实例。

但是,如果将本地定义的类的实例提升到顶级,则可以选择它们。

您必须设置本地类的__ qualname__类属性。然后,您必须将该类分配给同名的顶级变量。

def define_class(name):
    class local_class:
        pass
    local_class.__qualname__ = name
    return local_class

class_A = define_class('class_A') # picklable
class_B = define_class('class_B') # picklable
class_X = define_class('class_Y') # unpicklable, names don't match
Run Code Online (Sandbox Code Playgroud)