Possible to Unpickle class instances after being converted from old to new style?
在Python中,在转换为新样式的类之后,是否可以取消pickle作为旧样式的Python类的对象?(即具有不同"类签名"的对象)。*
例如,假设某些实例保存为:
然后在将类更改为从对象继承后,再处理几个对象:
1
| class foo(object): # new style |
带有一个pickle.dump的对象可以由同一样式类进行pickle.loaded,但两者都不能加载。我认为pickle使用的策略是基于继承而改变的(从对象继承的类有一个自动定义的_uuu reduce_uuu方法,但是没有继承的类没有)。当试图从没有继承的代码(旧样式定义)中加载带有继承的旧样式pickle时,我会得到与这个问题中相同的参数错误;即使第二个参数是多余的,它仍然会更改"类签名"和预期参数,并阻止加载。为了解决这个问题,我很乐意写一个unpickler,尽管我担心它可能涉及两个单独的子类unpickler a la the docs…如果我知道如何正确地拆开每一个,我就可以这样做了。
我的情况有点背景…我正在使用Trialhandler类为行为心理学实验保存和重新加载按钮和反应时间。我们将TrialHandler类重构为从更抽象的BaseTrialHandler继承,但这样做会暂时将类签名更改为从对象继承。但是,我们无法取消拾取旧的试用处理程序文件,因此它被改回。我想看看在两个版本的试用处理程序中运行的同一个实验中的数据,因此想在同一个脚本中取消选取两种类型的已保存日志文件。
或者,如果我不能编写一个自定义的取消拾取器来取消拾取这两个对象,还有其他方法来序列化它们吗?我试着直接把它扔给yaml,但是看起来我必须把这个类注册为可以被yaml化的东西。
有具体错误的问题的完整描述在精神病邮件列表中。任何解释中间酸洗,甚至是python继承细节的博客文章都是最受欢迎的;我发现最贴切的解释就是为什么酸洗是不安全的,把它描述成一个"简单的基于堆栈的虚拟机",这很好,但我还没有足够的时间去弄清楚自己拔的基础。
通过部件:
在python中没有所谓的"类签名",尽管我从你的问题中得到了这个想法
不从python 2程序中的"object"继承应该是认为是错误。不从对象继承的类-也称为"老风格"的课程,在那里只学习语言向后兼容性,当引入新样式类时python 2.2(大约是2000/2001年)-老式类要少得多一致性和缺乏许多特性,使得今天的Python好语言。
这样一来:unpickle将尝试根据类限定名反序列化对象,就像在.中一样,就像在pickle时对象的__class__.__name__属性中那样。因此,可能有一种简单的方法,即在unpickle异常(它引发typeerror)上,用相同的名称交换可用类,然后重试unpickle操作。同样:类应该从"对象"继承(更具体地说,有一个基于"类型"的元类)
关于我提到的例子,juust写了一些东西:
1 2 3 4 5 6 7
| try:
new_obj = pickle.load(data_stream)
except TypeError: # if you know this was caused due to the new version of"Foo" class:
current_foo = foomodule.Foo
foomodule.Foo = foomodule.OldFoo
new_obj = pickle.load(data_stream)
foomodule.Foo = current_foo |
- 好的建议——我没有意识到这是宣布新的和旧的风格类之间的关键区别。也许我应该将问题的标题改成"如何在将一个对象从旧样式转换为新样式后取消拾取?"我知道python没有严格的"签名"协议,有没有更好的方法来表达它?至少我会回去编辑,把签名放在引号里。
- 我想发布一个完整的例子,从交互式解释器中运行它——但是,我写的简化的旧样式类没有问题作为新样式被取消勾选。但是,我会同时声明这两个变量,在它们的名称中使用"old"和"new"sufixes("foo-old"和"foo-new"),将它们的__name__属性设置为"foo",并在取消拾取时动态地将模块"foo"变量设置为一个或另一个。
- 我考虑的是基于名称错误来进行救援,但是我没有同时提供foo和oldfoo,因为我将其中一个转换为另一个。最好的方法是什么?可能是什么?:class foo(object):new style def_uu init_uuu(self,…args):实际代码类oldfoo:old style def u init_uuu(self,…args):foo旧foo调用新的foo的地方(*args)?根据定义,旧样式类不能从新样式继承…有没有更好的方法,我不需要离开一个树桩旧风格的班?
- 另外,这个关于旧样式和新样式的问题也可以联系起来:stackoverflow.com/questions/10043963/…
- 我认为您最好有一个函数(或其他构造)来将对象从旧类型转换为新类型。您确实声明了这两个类(具有不同名称的旧类),并使用名称交换,如上所述取消拾取对象。然后恢复名称,调用converter函数以当前类定义实例化一个新对象,并根据传递的对象中的属性设置其属性。
- 这是有道理的-如果有任何问题,我会用一个简单的版本来验证它,并将其注册。谢谢!
- 虽然这是一个蹩脚的东西,但我构建了一些可以工作的概念验证代码。这可能不是我们离开它的方式,但它解决了这个问题。