关于shelve(Python)的奇怪问题

5 投票
6 回答
5189 浏览
提问于 2025-04-15 18:45

我创建了一个叫做 foo_module.py 的文件,里面有以下代码:

import shelve, whichdb, os

from foo_package.g import g

g.shelf = shelve.open("foo_path")
g.shelf.close() 

print whichdb.whichdb("foo_path")  # => dbhash
os.remove("foo_path")

然后我在这个文件旁边创建了一个叫做 foo_package 的文件夹,里面有一个空的 __init__.py 文件,还有一个叫 g.py 的文件,里面只包含:

class g:
    pass

现在,当我运行 foo_module.py 的时候,出现了一个奇怪的错误信息:

异常类型错误:"'NoneType' 对象不可调用" 被忽略

但是,如果我把文件夹的名字从 foo_package 改成 foo,并且在 foo_module.py 中修改导入的那一行,就不会出现任何错误了。这到底是怎么回事?

我在 WinXP 上运行 Python 2.6.4。

6 个回答

2

这确实是Python的一个bug,我已经在你打开的跟踪问题上提交了修复补丁(谢谢你这么做)。

问题在于,shelve的del方法会调用它的close方法,但如果shelve模块已经完成了清理工作,close方法就会失败,并显示你看到的错误信息。

你可以通过在g.shelf.close之后添加'del g.shelf'来避免这个错误信息。只要g.shelf是唯一指向这个shelf的引用,这样做就会让CPython立即调用shelve的del方法,在解释器的清理阶段之前,从而避免错误信息的出现。

10

经过几天的纠结,我终于成功地使用了一个叫做 atexit 的函数:

  import atexit
  ...
  cache = shelve.open(path)
  atexit.register(cache.close)

最好在打开之后立刻注册这个函数。这样在多个同时运行的程序中也能正常工作。

(这是在 lucid 上的 python 2.6.5 版本)

10

我觉得你在2.6.4版本的代码中遇到了一个小问题,这个问题和程序结束时的清理工作有关。如果你运行 python -v,你可以看到在清理过程中错误出现的具体时刻:

# cleanup[1] foo_package.g
Exception TypeError: "'NoneType' object is not callable" in  ignored

在程序结束时,Python会把一些引用设置为 None,看起来它对 g.shelf 的状态有些困惑。作为一个临时解决办法,你可以在 close 之后把 g.shelf 设置为 None。我还建议你在Python的错误追踪系统中提交一个bug报告!

撰写回答