2011-09-20 39 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

相關問題