2011-09-20 37 views
4

我正在使用python的内置搁置模块来管理一些简单的字典。我遇到的问题是我想使用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')  
+1

我们需要确切的错误信息。另外,上下文管理器不需要'__enter__'方法吗? – delnan

+0

我也有这个错误。我想知道是否与在系统上打开太多文件有关 - 用closing()封装它减少了打开的文件开销......用户agf的解决方案为我解决了它。 – NuclearPeon

回答

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()

+0

很干净的解决方案。谢谢。 –

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__”将自动调用。

+0

'type'是一个内建的;你不应该把它用作参数名称。 'traceback'也是一个标准的库模块,对于一个参数来说可能不是很好的名字,但是这不像前者那么重要。 – SingleNegationElimination

+0

@TokenMacGuy - 确实如此。我将调整参数名称为'__exit__'。 –

+0

使用'contextlib.closing()'返回的对象是所需类型的实例,而不是子类的实例,但除此之外,它基本上是相同的:http://hg.python.org/cpython/file/ 2.7/Lib/contextlib.py#l132 – agf

相关问题