Самый простой способ добавить функцию в существующий класс - PullRequest
4 голосов
/ 20 сентября 2011

Я использую встроенный модуль полки 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')    

Ответы [ 2 ]

12 голосов
/ 20 сентября 2011

Не делайте это на подклассы. Python поставляется с инструментом для автоматического вызова close(), contextlib.closing:

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

автоматически вызовет метод close() объекта, возвращаемого shelve.open(filename) в конце блока with.

2 голосов
/ 20 сентября 2011

Вы наследуете не ту вещь и пропускаете метод __enter__. Вы, вероятно, хотите это:

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

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

Поскольку вы добавляете методы, но не изменяете сигнатуру __init__ или не добавляете какие-либо дополнительные шаги, нет причин для переопределения __init__. Базовый класс '__init__ будет вызываться автоматически.

...