Python搁置忽略writeback = True

时间:2014-05-14 10:04:27

标签: python shelve

我遇到的问题是列表中的更改未反映在关联的架子中(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 shell上重现它。输出ID相同,并且保存列表显示jobQueue上的更改。
似乎在执行我的程序时,writeback=True被忽略。我很满意每一个提示!

编辑:我确实使用给定的最小示例重现了shell上的问题。这可能与类结构有关(我对客观Python很新)?我可以想象,类Cont不知道类T,因此不能存储对T.jobQueue的引用,而是存储列表的副本。

2 个答案:

答案 0 :(得分:3)

没有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]
  1. 如果writeback = True,则赋值会将shelf / value对存储在shelf.cache以及shelf.dict中。
  2. 尝试从shelf.cache中的密钥'queue'检索数据。
  3. 修改cls.jobQueue,其中 与该对象相同 从缓存中检索
  4. 再次从shelf.cache检索密钥'queue'的数据。由于缓存保持对cls.jobQueue的反射,因此这是同一个对象。
  5. 但是,如果您调用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]
    
    1. 搁置文件已更新and the cache is reset to an empty dict
    2. 尝试从shelf.cache检索密钥'queue'的数据。由于缓存为空,因此从搁置文件中检索数据的新副本
    3. 修改cls.jobQueue,其中不是与刚刚检索到的副本相同的对象
    4. 缓存仍为空,因此会再次从未更新的搁置文件中检索新副本

答案 1 :(得分:0)

经过大量测试后我发现了问题:
Cont.shelf.sync()更改了shelf中包含的数据的id(和引用)。因此cls.jobQueue调用后.sync()的变化不会反映出来 虽然搁置模块的documentation并没有像我那样禁止使用它,但它似乎只能以记录的方式正常工作。这意味着所有更改都应如下所示:
Cont.shelf['queue'].pop()
或者在每次修改后重新分配jobQueue到货架上。