为什么我未腌制的顺序与腌制时的顺序不同?
Why is my unpickled sequence different than when it was pickled?
我对 python 变量持久性有点困惑,在我的代码中,我使用以下代码使模型参数在某些迭代期间持久化
with open('W_Hs_Hu_iter'+str(inx)+'.pickle', 'wb') as f:
pickle.dump((self.W,self.Hs,self.Hu),f)
经过长时间的迭代,我尝试用
加载模型
with open('W_Hs_Hu_iter450.pickle', 'rb') as f:
W,Hs,Hu= pickle.load(f)
#W,Hu,Hs= pickle.load(f)
可是我查了一下,Hs和Hu的顺序错了?那会发生吗?
我同意@peter-wood 的观点,它看起来是正确的,而且我已经对其进行了测试以确保。
import pickle
class TestObj(object):
def __init__(self, one=1, two=2, three=3):
self.one = one
self.two = two
self.three = three
def save(self):
with open('D:\test.pickle', 'wb') as f:
pickle.dump((self.one,self.two,self.three),f,-1)
@staticmethod
def load():
with open('D:\test.pickle', 'rb') as f:
one,two,three = pickle.load(f)
test_obj = TestObj(one, two, three)
return test_obj
test_obj = TestObj() #Init with defaults
test_obj.save()
print 'after save: one: %s, two: %s, three: %s' % (test_obj.one,test_obj.two,test_obj.three)
test_obj = test_obj.load()
print 'after load: one: %s, two: %s, three: %s' % (test_obj.one,test_obj.two,test_obj.three)
我最好的猜测是,当您保存时,Hs
和 Hu
的值已经交换了。在保存之前执行 log\print。
这是一个 class 实例的 pickle,其中属性值在 pickle 后交换。
>>> class Foo(object):
... a = 1
... b = 2
... def __init__(self, c,d):
... self.c = c
... self.d = d
... def bar(self):
... return self.a,self.b,self.c,self.d
...
>>> f = Foo(3,4)
>>> _f = pickle.dumps(f)
>>> f.c,f.d = f.d,f.c
>>> f.b,f.a = f.a,f.b
>>> f_ = pickle.loads(_f)
>>> f_.bar()
(1, 2, 3, 4)
>>> f.bar()
(2, 1, 4, 3)
所以,这按预期工作。然而,python pickles classes 通过引用,所以如果你改变 class 定义,它似乎会改变实例属性。
>>> g = Foo(3,4)
>>> _g = pickle.dumps(g)
>>> g.c,g.d = g.d,g.c
>>> Foo.a,Foo.b = Foo.b,Foo.a
>>> g_ = pickle.loads(_g)
>>> g_.bar()
(2, 1, 3, 4)
>>> g.bar()
(2, 1, 4, 3)
如果您将列表或其他一些序列作为 class 属性,这一点会更加明显。因此,让我们向 class.
添加一些列表对象
>>> Foo.a = []
>>> Foo.zap = lambda self:self.a
>>> Foo.baz = lambda self,x:self.a.append(x)
>>>
>>> h = Foo(3,4)
>>> h.baz(0)
>>> h.baz(1)
>>> h.zap()
[0, 1]
>>> _h = pickle.dumps(h)
>>> h.baz(2)
>>> h.baz(3)
>>> h_ = pickle.loads(_h)
>>> h_.zap()
[0, 1, 2, 3]
这是因为列表的值实际上存储在 class 属性而不是实例属性上。这是此类行为的众多示例之一。
如果您想保留实例 "as is"(即不通过引用存储),那么您应该使用 dill
进行 pickle。然而,dill
的泡菜会更大。
>>> import dill
>>> _h = dill.dumps(h)
>>> h.baz(4)
>>> h.baz(5)
>>> h_ = dill.loads(_h)
>>> h_.zap()
[0, 1, 2, 3]
>>> h.zap()
[0, 1, 2, 3, 4, 5]
我对 python 变量持久性有点困惑,在我的代码中,我使用以下代码使模型参数在某些迭代期间持久化
with open('W_Hs_Hu_iter'+str(inx)+'.pickle', 'wb') as f:
pickle.dump((self.W,self.Hs,self.Hu),f)
经过长时间的迭代,我尝试用
加载模型with open('W_Hs_Hu_iter450.pickle', 'rb') as f:
W,Hs,Hu= pickle.load(f)
#W,Hu,Hs= pickle.load(f)
可是我查了一下,Hs和Hu的顺序错了?那会发生吗?
我同意@peter-wood 的观点,它看起来是正确的,而且我已经对其进行了测试以确保。
import pickle
class TestObj(object):
def __init__(self, one=1, two=2, three=3):
self.one = one
self.two = two
self.three = three
def save(self):
with open('D:\test.pickle', 'wb') as f:
pickle.dump((self.one,self.two,self.three),f,-1)
@staticmethod
def load():
with open('D:\test.pickle', 'rb') as f:
one,two,three = pickle.load(f)
test_obj = TestObj(one, two, three)
return test_obj
test_obj = TestObj() #Init with defaults
test_obj.save()
print 'after save: one: %s, two: %s, three: %s' % (test_obj.one,test_obj.two,test_obj.three)
test_obj = test_obj.load()
print 'after load: one: %s, two: %s, three: %s' % (test_obj.one,test_obj.two,test_obj.three)
我最好的猜测是,当您保存时,Hs
和 Hu
的值已经交换了。在保存之前执行 log\print。
这是一个 class 实例的 pickle,其中属性值在 pickle 后交换。
>>> class Foo(object):
... a = 1
... b = 2
... def __init__(self, c,d):
... self.c = c
... self.d = d
... def bar(self):
... return self.a,self.b,self.c,self.d
...
>>> f = Foo(3,4)
>>> _f = pickle.dumps(f)
>>> f.c,f.d = f.d,f.c
>>> f.b,f.a = f.a,f.b
>>> f_ = pickle.loads(_f)
>>> f_.bar()
(1, 2, 3, 4)
>>> f.bar()
(2, 1, 4, 3)
所以,这按预期工作。然而,python pickles classes 通过引用,所以如果你改变 class 定义,它似乎会改变实例属性。
>>> g = Foo(3,4)
>>> _g = pickle.dumps(g)
>>> g.c,g.d = g.d,g.c
>>> Foo.a,Foo.b = Foo.b,Foo.a
>>> g_ = pickle.loads(_g)
>>> g_.bar()
(2, 1, 3, 4)
>>> g.bar()
(2, 1, 4, 3)
如果您将列表或其他一些序列作为 class 属性,这一点会更加明显。因此,让我们向 class.
添加一些列表对象>>> Foo.a = []
>>> Foo.zap = lambda self:self.a
>>> Foo.baz = lambda self,x:self.a.append(x)
>>>
>>> h = Foo(3,4)
>>> h.baz(0)
>>> h.baz(1)
>>> h.zap()
[0, 1]
>>> _h = pickle.dumps(h)
>>> h.baz(2)
>>> h.baz(3)
>>> h_ = pickle.loads(_h)
>>> h_.zap()
[0, 1, 2, 3]
这是因为列表的值实际上存储在 class 属性而不是实例属性上。这是此类行为的众多示例之一。
如果您想保留实例 "as is"(即不通过引用存储),那么您应该使用 dill
进行 pickle。然而,dill
的泡菜会更大。
>>> import dill
>>> _h = dill.dumps(h)
>>> h.baz(4)
>>> h.baz(5)
>>> h_ = dill.loads(_h)
>>> h_.zap()
[0, 1, 2, 3]
>>> h.zap()
[0, 1, 2, 3, 4, 5]