向现有类添加函数的最简单方法

4 投票
2 回答
1305 浏览
提问于 2025-04-17 02:42

我正在使用Python自带的shelve模块来管理一些简单的字典。现在我遇到的问题是,我想用 with shelve.open(filename) as f: 这种方式来打开文件,但当我这么做时,它告诉我DbfilenameShelf没有 __exit__ 这个属性。

所以,我在想,最简单的解决办法就是把它放在另一个类里,并给这个包装类添加一个 __exit__ 函数。我尝试了这样做:

class Wrapper(shelve.DbfilenameShelf):
    def __exit__(self):
        self.close()
    def __init__(self, filename, writeback=False):
        shelve.DbfilenameShelf.__init__(self, filename, flag='c', protocol=None, writeback=False)

但是当我试图像这样实例化这个包装类: wrapped = Wrapper(filename) 时,它告诉我我给了它一个无效的参数。

错误信息如下:

Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 5, in __init__
File "C:\Python27\Lib\shelve.py", line 223, in __init__
Shelf.__init__(self, anydbm.open(filename, flag), protocol, writeback)
File "C:\Python27\Lib\anydbm.py", line 85, in open
return mod.open(file, flag, mode)
File "C:\Python27\Lib\dbhash.py", line 18, in open
return bsddb.hashopen(file, flag, mode)
File "C:\Python27\Lib\bsddb\__init__.py", line 364, in hashopen
d.open(file, db.DB_HASH, flags, mode)
DBInvalidArgError: (22, 'Invalid argument')    

2 个回答

2

你正在继承错误的东西,并且缺少一个 __enter__ 方法。你可能想要的是这个:

class contextShelf(shelve.shelve):
  def __enter__(self):
    return self

  def __exit__(self, exc_type, exc_value, exc_trace):
    self.close()

因为你只是添加了一些方法,但没有改变 __init__ 的签名,也没有增加任何额外的步骤,所以其实没有必要重新定义 __init__。基础类的 __init__ 会自动被调用。

12

不要去继承它。Python 提供了一个工具,可以自动调用 close() 方法,这个工具叫做 contextlib.closing

from contextlib import closing
with closing(shelve.open(filename)) as f:
    # your 'with' block here

with 代码块结束时,它会自动调用由 shelve.open(filename) 返回的对象的 close() 方法。

撰写回答