将额外字段添加到现有的namedtuple对象并进行unpickling

时间:2017-12-27 22:39:50

标签: python python-2.7 pickle namedtuple

我有一些带有以下对象实例的pickle格式数据:

Point = namedtuple('Point', ['x',])

现在我想扩展Point对象以添加另一个变量'y',但也保持与我已经腌制的数据兼容。

以下是我尝试过的,但似乎失败了。我还尝试使用代码来创建一个Point类,方法是在创建Point对象时将y参数设置为可选,但是这也不起作用。关于如何进行的任何想法?

from collections import namedtuple
Point = namedtuple('Point', ['x'])
i = Point(1)
import cPickle
pick=cPickle.dumps(i)
Point = namedtuple('Point', ['x', 'y'])
cPickle.loads(pick)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 22, in __repr__
TypeError: not enough arguments for format string

2 个答案:

答案 0 :(得分:2)

元组是不可变的。 首先取消,而不是使用不同的namedtuple类创建一个新点,并使用旧点的属性x。 对类Point使用相同的名称应具有以下效果:

Point = namedtuple('Point', ['x'])
i = Point(1)
pick=cPickle.dumps(i)


def unpickle_point(dumped_obj):
    Point = namedtuple('Point', ['x'])
    point = cPickle.loads(pick)
    Point = namedtuple('Point', ['x', 'y'])
    return Point(point.x, 2)

new_point = unpickle_point(pick)

现在:

>>> new_point
Point(x=1, y=2)

答案 1 :(得分:0)

如果您要求:

  1. 当名称I am trying for 2 hours to get this working but no luck.一个参数有关时,unpickler将获取字符串;但
  2. 当时,Point表示使用两个参数生成的内容
  3. ...然后,你可以通过要求不可能的事情将自己画成一个角落。默认情况下,pickling和unpickling都是通过编码(pickle)和解码(unpickle) all 与对象一起使用的值来完成的。名为Point的对象具有一个值。不,它有两个值!好吧,选择其中一个:它不能兼得。

    您可以像在Mike Müller's answer中一样,使名称Point在unpickling的持续时间内引用单值Point,然后将名称Point引用之后是两值Point。这将起作用,代价是大量的类型定义和名称操作。您可以通过不重新创建类型本身来降低总体成本(非常显着)。方法如下:

    Point

    此代码也适用于Python 3(假设您从from collections import namedtuple import sys Point = namedtuple('Point', ['x']) i = Point(1) import cPickle pick = cPickle.dumps(i) old_style_point = Point Point = namedtuple('Point', ['x', 'y']) def unpickle_point(dumped_obj): """Make main.Point refer to the old style point for the duration of the pickle.loads() operation, then back to the new style Point afterward.""" mod = sys.modules[__name__] # eg, sys.modules['__main__'] save = mod.__dict__['Point'] try: mod.__dict__['Point'] = old_style_point old_point = cPickle.loads(dumped_obj) finally: mod.__dict__['Point'] = save return Point(old_point.x, 2) t = unpickle_point(pick) print(t) 切换到cPickle)。这里的pickle / try序列表示如果您在错误数据上运行此序列,则类型名称finally将继续引用 new {{1}对象,而不是Point中的旧对象。但是,与往常一样,腌制字符串并不安全,如果您不相信它们,则根本不应该这样做,因此如果数据是Point / old_style_point,则可以删除try / finally这一特定位。值得信赖的。 (但是你这样做的事实表明数据不是值得信赖的。)