为什么搁置不知道何时对可变对象进行了更改?

Why doesn't shelve know when a change has been made to a mutable object?

我目前正在学习 Python 编程方面的在线 Udemy 课程,我们正在学习搁置模块。教授已经表明,出于某种原因,搁置无法知道何时更改了可变对象,如下所示:(他也解释了解决方法)

import shelve

# Making a bunch of lists to bind to shelves later
blt = ["bacon", "tomato", "lettuce", "bread"]
beans_on_toast = ["beans", "bread"]
scrambled_eggs = ["eggs", "butter", "milk"]
soup = ["tin of soup"]
pasta = ["pasta", "cheese"]


with shelve.open('recipes') as recipes:
    # Binding each list to a shelve
    recipes['blt'] = blt
    recipes['beans on toast'] = beans_on_toast
    recipes['scrambled eggs'] = scrambled_eggs
    recipes['pasta'] = pasta
    recipes['soup'] = soup

    # Attempting to append 'butter' and 'tomato' to respective lists
    recipes['blt'].append("butter")
    recipes['pasta'].append("tomato")

    for snack in recipes:
        print(snack, recipes[snack])

for 循环的输出显示货架未更改,值 'butter' 和 'tomato' 未附加到各自的货架。

我的在线教授试图解释为什么会这样,但我无法理解。如果有人可以尝试向我解释,我将不胜感激。

如果您有耐心,能否解释一下您在回答中可能使用的任何您认为我无法理解的术语。我还是初学者,Python 是我学习的第一门语言。提前致谢!

将您的 recipes 架子想象成厨房中的物理食谱书。

recipes['blt'] = blt在书上写了一个食谱,可以做一道像blt这样的菜。

访问recipes['blt']根据食谱制作菜肴。

recipes['blt'].append("butter")做一道菜,然后加入黄油。书中的食谱并没有突然涉及黄油;如果您想重写食谱,则必须单独进行。


这基本上就是 shelve 的工作原理。 Shelf 对象由磁盘上的数据文件支持,文件中的每个条目都包含用于构建对象的说明(采用 pickle 格式)。访问货架会根据存储的指令构建一个对象,但更改您构建的对象不会更改指令。

如果您使用 writeback=True 创建 shelf,则不会在每次访问条目时构建新对象,shelf 将缓存构建的对象和 return 相同的对象,如果您再次访问相同的条目。它仍然不知道您何时更改任何内容,但由于它是 return 同一个对象,因此更改仍然存在。

当您关闭 writeback=True 架子时,架子将在架子关闭时为对象写入新的泡菜。新泡菜将反映对对象的任何更改。这可能涉及很多不必要的编写,因为 shelf 实际上仍然不知道您何时更改了对象,因此它必须重新 pickle 所有对象,即使是未更改的对象。