6

在 python 中,是否有可能在转换为新样式后取消腌制为旧样式 python 类的对象?(即,具有不同“类签名”的对象)。*

例如,假设某些实例被保存为:

class foo: # old style

然后在将类更改为从对象继承后腌制了更多对象:

class foo(object): # new style

用一个 'ed 的对象pickle.dump可以被pickle.load同一个样式类 'ed,但任何一个都不会加载两者。我认为pickle使用的策略会根据继承发生变化(从对象继承的类有一个自动定义的 __reduce__ 方法,但没有继承的类没有)。当尝试从没有继承的代码(旧式定义)中加载带有继承性的旧式泡菜时,我得到与此SO question中看到的相同的参数错误;即使第二个参数是多余的,它仍然会更改“类签名”和预期的参数,并阻止加载。为了解决这个问题,我很乐意编写一个 unpickler,尽管我担心它可能涉及两个单独的子类 unpicklers a la the docs...如果我知道如何正确地解开每一个,我会很好地做到这一点。

关于我的情况的一点背景......我正在使用 TrialHandler 类来保存和重新加载按钮按下和反应时间以进行行为心理学实验。我们重构了 TrialHandler 类以从更抽象的 baseTrialHandler 继承,但这样做暂时将类签名更改为从object继承。但是,我们无法解开旧的 trial_handler 文件,所以它被改回来了。我想查看使用两个版本的试验处理程序运行的同一实验的数据,因此想在同一个脚本中取消两种类型的已保存日志文件。

或者,如果我不能编写一个自定义 unpickler 来解开两个对象,是否有另一种方法来序列化它们?我尝试直接转储到 yaml,但看起来我必须将类注册为可以被 yaml 化的东西,无论如何。

PsychoPy 邮件列表中包含特定错误问题的完整描述。任何解释中间酸洗细节的博客文章,甚至是 python 继承,都将受到欢迎;我发现的最接近的是一个很好的解释为什么酸洗是不安全的,将酸洗描述为“简单的基于堆栈的虚拟机”,这很好,但并不足以让我弄清楚我自己的基础知识。

4

1 回答 1

5

遍历部分:

  1. Python中没有所谓的“类签名”,虽然我从你的问题中得到了这个想法
  2. 不从 Python 2 程序中的“对象”继承应被视为错误。不从对象继承的类 - 也称为“旧样式”类,只是为了向后兼容而保留在语言上,当在 Python 2.2 中引入新样式类时(大约 2000/2001 年) - 旧样式类的一致性要低得多并且缺乏许多使今天的 python 成为如此好的语言的特性。

顺便说一句:unpickle 将尝试根据类限定名称反序列化对象 - 如在酸洗时<module>.<class>对象的属性中所示。__class__.__name__所以有可能有一种天真的方式,在 unpickle 异常(它引发 TypeError)上,交换具有相同名称的可用类,然后再次重试 unpickle 操作:你的类应该继承自“object”(更具体地说,有一个基于“类型”的元类)

至于我提到的例子,只要写一些东西:

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
于 2012-04-06T03:49:33.890 回答