在Python pickle: dealing with updated class definitions的回答中,dill
包的作者写道:
“好的,我已经在github的最新版本中添加了这个功能。用比我想象的更少的技巧实现...只需用pickle序列化类定义,瞧。”
安装了dill
并修改了它后,对我来说,如何在dill
中实际使用此功能并不明显。有人能提供一个明确的例子吗?我想挑选类实例并序列化类定义。
(我是python的新手,我的这个功能似乎非常重要,因为当腌制一个对象时,尽可能接近保证你可以看到对象会很好(可能是一个结果)模拟)在类定义可能已经改变之后的未来,并且您没有以易于访问的方式跟踪所有更改。)
答案 0 :(得分:7)
我认为您正在寻找以下功能之一......
这里我构建一个类和一个实例,然后更改类定义。
由于dill
泡菜,腌制的类和实例仍然是不可销售的
默认情况下,该类的源代码...并管理有几个类
在命名空间中具有相同的名称(它只是通过管理指针来完成此操作
对类定义的引用。)
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>>
>>> class Foo(object):
... def bar(self, x):
... return x+self.y
... y = 1
...
>>> f = Foo()
>>> _Foo = dill.dumps(Foo)
>>> _f = dill.dumps(f)
>>>
>>> class Foo(object):
... def bar(self, x):
... return x*self.z
... z = -1
...
>>> f_ = dill.loads(_f, ignore=True)
>>> f_.y
1
>>> f_.bar(1)
2
>>> Foo_ = dill.loads(_Foo)
>>> g = Foo_()
>>> g.bar(1)
2
Pickle会在上面爆炸。如果您不希望dill
明确地序列化该类,并执行pickle
所做的操作,那么您可以通过dill
引用dill.dumps(Foo, byref=True)
来挑选。或者,您可以使用ignore=False
(默认值)动态决定忽略新定义的类。
现在,在下面的例子中,我们使用新的类定义,并提取源 从对象,然后将其保存到文件。另外,我们可以将源转储到文件(这里我使用临时文件),以便稍后导入。
>>> sFoo = dill.source.getsource(Foo)
>>> print sFoo
class Foo(object):
def bar(self, x):
return x*self.z
z = -1
>>> open('myFoo.py', 'w').write(sFoo)
>>>
>>> f = dill.temp.dump_source(Foo, dir='.')
>>> f.name
'/Users/mmckerns/dev/tmpM1dzYN.py'
>>> from tmpM1dzYN import Foo as _Foo_
>>> h = _Foo_()
>>> h.bar(2)
-2
>>> from myFoo import Foo as _SFoo_
>>> _SFoo_.z
>>> -1
>>>
我希望有所帮助。
答案 1 :(得分:5)
如果这个功能非常重要,那么它现在将成为语言核心。 :-) 所以,不,这对于以任何高级形式使用Python并不重要 - 如果你有一个依赖于能够基于旧模型重新实例化对象的项目 - 这是可能的,你必须仔细考虑它,并且可能在显式代码中保留旧模型,而不是随后序列化。
我的建议只是"将其分开"直到你认为你真的需要它,并将其与其他解决方案进行比较,比如强大的模型迁移政策。
那就是说,我已经尝试了莳萝,它的工作方式与广告一样:它可以序列化一个类 就像pickle可以使用" dump"和"转储"调用,并使用" load"重建类对象。和#34;加载"。
让您感到困惑的是,序列化对象(通过pickle或dill等)不包括其源代码(即用于定义类的文本Python代码的实际行),也不包括其名称。
因此,如果一个类被命名为" A",当它被序列化时,如果你需要那个名字" undilling"它,你必须在全局名称空间中重新分配该名称。它的原始名称保留在__name__
属性中。 (并且出于同一模型的多个版本共同生活的目的,这将导致很多冲突)。
因此:
class A(object):
...
import dill
dill.dump(A, open("myfile", "w"))
del A
....
someclass = dill.load(open("myfile"))
print (someclass.__name__)
globals()[someclass.__name__] = someclass
# at this point you have the "A" class back in the global namespace