我认为解释这种情况的最好方法是举一个例子:
>>> class Person:
... def __init__(self, brother=None):
... self.brother = brother
...
>>> bob = Person()
>>> alice = Person(brother=bob)
>>> import shelve
>>> db = shelve.open('main.db', writeback=True)
>>> db['bob'] = bob
>>> db['alice'] = alice
>>> db['bob'] is db['alice'].brother
True
>>> db['bob'] == db['alice'].brother
True
>>> db.close()
>>> db = shelve.open('main.db',writeback=True)
>>> db['bob'] is db['alice'].brother
False
>>> db['bob'] == db['alice'].brother
False
两次比较的预期输出再次为
True
。但是,pickle
(由shelve
使用)似乎分别重新实例化了bob
和alice.brother
。如何使用shelve
/ pickle
“修复”此问题? db['alice'].brother
是否可能指向db['bob']
或类似的东西?请注意,我不想只比较两者,实际上我需要两者都相同。正如Blckknght所建议的那样,我尝试立即对整个词典进行酸洗,但是问题仍然存在,因为它似乎分别酸洗每个键。
最佳答案
我相信您看到的问题来自shelve
模块存储其值的方式。每个值的酸洗都独立于架子中的其他值,这意味着,如果将同一对象作为一个值插入到多个键下,则不会在键之间保留身份。但是,如果单个值具有对同一对象的多个引用,则身份将保持在该单个值内。
这是一个例子:
a = object() # an arbitrary object
db = shelve.open("text.db")
db['a'] = a
db['another_a'] = a
db['two_a_references'] = [a, a]
db.close()
db = shelve.open("text.db") # reopen the db
print(db['a'] is db['another_a']) # prints False
print(db['two_a_references'][0] is db['two_a_references'][1]) # prints True
第一次打印尝试确认插入到数据库中的对象
a
的两个版本的身份,一个版本直接在键'a'
下,另一个在'another_a'
下。这是行不通的,因为单独的值是单独腌制的,因此它们之间的标识丢失了。第二张印刷品测试是否保留了键
a
下存储的对'two_a_references'
的两个引用。因为清单是一次性腌制的,所以保留了身份。因此,要解决您的问题,您有几种选择。一种方法是避免测试身份,并依靠各种对象类型中的
__eq__
方法来确定两个对象在语义上是否相等,即使它们不是同一对象。另一个方法是将所有数据捆绑到一个对象(例如字典)中,然后使用pickle.dump
保存并使用pickle.load
还原而不是使用shelve
(或者您可以使用this recipe for a persistent dictionary从shelve
文档链接,并完成了很多工作)。关于python - 关闭架子后,存储在架子中的Python实例会发生变化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17636226/