【问题标题】:Pickle linked objectsPickle 链接对象
【发布时间】:2011-06-16 17:31:09
【问题描述】:

我想腌制一个对象和引用第一个对象的第二个对象。当我天真地腌制/解开这两个对象时,引用就变成了副本。如何保留foobar.foo_ref 两个对象之间的链接?

import pickle

class Foo(object):
    pass

foo = Foo()
bar = Foo()
bar.foo_ref = foo

with open('tmp.pkl', 'wb') as f:
    pickle.dump(foo, f)
    pickle.dump(bar, f)
with open('tmp.pkl', 'rb') as f:
    foo2 = pickle.load(f)
    bar2 = pickle.load(f)

print id(foo) == id(bar.foo_ref) # True
print id(foo2) == id(bar2.foo_ref) # False
# want id(foo2) == id(bar2.foo_ref)

【问题讨论】:

  • 我认为您不能在单独的泡菜中保留对象身份。如果你有一个包含 foo 和 bar 的主对象 x,并且在你解开它时腌制它 id(x.foo) == id(x.bar.foo_ref)

标签: python pickle


【解决方案1】:

我之前的回答没有抓住你的意思。您的代码的问题在于您没有使用 PicklerUnpickler 对象。这是一个带有多个转储调用的工作版本:

import pickle

class Foo(object):
    pass

foo = Foo()
bar = Foo()
bar.foo_ref = foo

f = open('tmp.pkl', 'wb')
p = pickle.Pickler(f)
p.dump(foo)
p.dump(bar)
f.close()

f = open('tmp.pkl', 'rb')
up = pickle.Unpickler(f)
foo2 = up.load()
bar2 = up.load()

print id(foo) == id(bar.foo_ref) # True
print id(foo2) == id(bar2.foo_ref) # True

【讨论】:

【解决方案2】:

如果将它们腌制在一起,pickle 模块会跟踪引用并且只腌制一次foo 变量。你能像这样把foobar 一起腌制吗?

import pickle

class Foo(object):
    pass

foo = Foo()
bar = Foo()
bar.foo_ref = foo

with open('tmp.pkl', 'wb') as f:
    pickle.dump((foo, bar), f)
with open('tmp.pkl', 'rb') as f:
    foo2, bar2 = pickle.load(f)

print id(foo) == id(bar.foo_ref) # True
print id(foo2) == id(bar2.foo_ref) # True

【讨论】:

  • 根据文档,这不应该是必要的,因为pickle 应该跟踪它已序列化的对象,而不是在引用已经序列化的对象时重新提取。跨度>
  • @JAB 我以为只有一次调用转储,而不是多次调用转储到同一个文件?
  • 这行得通,但如果您希望能够多次调用 dump,您可以使用 PicklerUnpickler 对象来实现。有关详细信息,请参阅我的其他答案。
【解决方案3】:

好吧,你能做到吗:

bar2 = pickle.load(f)
foo2 = bar2.foo_ref

让pickle为你处理链接。

【讨论】:

  • 谢谢,但我不想手动处理引用层次结构。
猜你喜欢
  • 1970-01-01
  • 2018-06-07
  • 1970-01-01
  • 1970-01-01
  • 2022-12-22
  • 1970-01-01
  • 2018-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多