Python shelve 忽略 writeback=True
我遇到了一个问题,就是在一个列表里的变化没有反映到关联的存储上(使用的是Python 2.6.9)。下面是一个简单的例子。
文件 Context.py:
import shelve
class Cont:
shelf = shelve.open( STATUSFILE, protocol = 0, writeback = True )
文件 test.py:
from Context import Cont
class T:
jobQueue = list()
@classmethod
def save(cls):
cls.jobQueue = [1,2,3]
Cont.shelf['queue'] = cls.jobQueue
Cont.shelf.sync()
print(Cont.shelf['queue'])
cls.jobQueue.pop()
print(Cont.shelf['queue'])
print(id(cls.jobQueue))
print(id(Cont.shelf['queue']))
输出结果:
[1,2,3]
[1,2,3]
7804904
7899472
首先,我原本以为第二个列表的输出是[1,2]
。其次,为什么它们的ID不同呢?在给列表赋值的时候,应该只是复制一个引用,而ID应该保持不变。
奇怪的是,我在Python的命令行里无法重现这个问题。在那里,输出的ID是相同的,而且存储的列表也显示了jobQueue的变化。
看起来在执行我的程序时,writeback=True
这个设置被忽略了。我非常感谢任何提示!
编辑:我在命令行里用这个简单的例子重现了这个问题。这可能和类的结构有关(我对面向对象的Python还很陌生)?我可以想象,类Cont并不知道类T,因此不能存储对T.jobQueue的引用,而是存储了列表的一个副本。
2 个回答
0
经过很多测试,我找到了问题所在:
这行代码 Cont.shelf.sync()
会改变存储在shelf里的数据的ID(和引用)。所以在调用 .sync()
之后,cls.jobQueue
的变化就不会被反映出来。
虽然shelve模块的文档并没有禁止我这样使用,但它似乎只有按照文档中的方式才能正常工作。这意味着所有的修改都应该这样进行:
Cont.shelf['queue'].pop()
或者在每次修改后,把 jobQueue
重新赋值给shelf。
4
如果不使用 shelf.sync():
def save(cls):
Cont.shelf['queue'] = cls.jobQueue #1
print(Cont.shelf['queue']) #2
# [1, 2, 3]
cls.jobQueue.pop() #3
print(Cont.shelf['queue']) #4
# [1, 2]
- 当设置为 writeback=True 时,赋值操作会把键值对同时存储在 shelf.cache 和 shelf.dict 中。
- 尝试从 shelf.cache 中获取键为
'queue'
的数据。 - 修改
cls.jobQueue
,这个对象和从缓存中获取的对象是同一个。 - 再次从 shelf.cache 中获取键为
'queue'
的数据。因为缓存中保存了对cls.jobQueue
的引用,所以这次获取的还是同一个对象。
但是,如果你调用 shelf.sync():
def save(cls):
Cont.shelf['queue'] = cls.jobQueue
Cont.shelf.sync() #1
print(Cont.shelf['queue']) #2
# [1, 2, 3]
cls.jobQueue.pop() #3
print(Cont.shelf['queue']) #4
# [1, 2, 3]
- 会更新 shelve 文件,并且缓存会被重置为空字典。
- 尝试从 shelf.cache 中获取键为
'queue'
的数据。因为缓存是空的,所以会从 shelve 文件中获取数据的新副本。 - 修改
cls.jobQueue
,这个对象和刚刚获取的副本不是同一个。 - 缓存仍然是空的,所以这次又会从未更新的 shelve 文件中获取一个新副本。