我有一些带有以下对象实例的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
答案 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)
如果您要求:
I am trying for 2 hours to get this working but no luck.
与一个参数有关时,unpickler将获取字符串;但Point
表示使用两个参数生成的内容 ...然后,你可以通过要求不可能的事情将自己画成一个角落。默认情况下,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
这一特定位。值得信赖的。 (但是你这样做的事实表明数据不是值得信赖的。)