О чем следует помнить при использовании оператора with для собственных классов? - PullRequest
8 голосов
/ 18 января 2012

Я планирую реализовать C ++ -подобную функциональность конструктора / деструктора в одном из моих классов Python, используя удобный оператор с . До сих пор я сталкивался с этим утверждением только для файлового ввода-вывода, но я подумал, что это будет весьма полезно и для задач связи на основе соединений, скажем сокеты или подключения к базе данных . Вещи, которые в конечном итоге должны быть закрыты.

В PEP 343 (ссылка выше) говорится, что для with нужны методы __enter__ и __exit__, и моя прямая реализация этого, похоже, работает как задумано.

class MyConnection:
  def __init__(self):
    pass
  def __enter__(self):
    print "constructor"
    # TODO: open connections and stuff
    # make the connection available in the with-block
    return self 
  def __exit__(self, *args):
    print "destructor"
    # TODO: close connections and stuff

with MyConnection() as c:
  # TODO: do something with c
  pass

Что дает результат (как и ожидалось):

constructor
destructor

Должно ли это быть так просто? Что нужно учитывать помимо этого? Почему так много библиотек (очевидно) еще не имеют этой функциональности? Я что-то пропустил?

Ответы [ 2 ]

5 голосов
/ 18 января 2012

(а) Это так просто

(b) Альтернативным подходом является функция декоратора, которая украшает функции (и классы, но не для этого варианта использования), а также позволяет вызывать код как до, так и после упакованной функции. Они кажутся немного более распространенными.

(с) Я не думаю, что вы что-то упускаете.

0 голосов
/ 19 января 2012

Одна проблема, с которой я столкнулся при попытке реализовать функцию «с» в моих библиотеках, - это изысканный способ обработки исключений при сбое.Учитывая следующее:

class open_file_for_read(object):
    def __init__(self):
        self.filename = "./does_not_exist.txt"
        self.fileobj = None

    def __enter__(self):
        print("Opening file %s for read" % self.filename)
        self.fileobj = open(name=self.filename, mode='r')
        return self.fileobj

    def __exit__(self, type, value, traceback):
        self.fileobj.close()


with open_file_for_read() as fh:
    for li in fh.readlines():
        print(li)

Каков рекомендуемый метод для обработки неизбежного «IOError: [Errno 2] Нет такого файла или каталога: исключение './does_not_exist.txt'»?Всегда есть подход «попробуй / кроме»

try:
    with open_file_for_read() as fh:
except IOError:
    ...
except XXX:
    ...
...

Этот прямой подход работает, но я думаю, что он умаляет простоту использования конструкции «с».Возможно, у кого-то есть более элегантное решение?

Извинения за то, что это скорее вопрос, чем ответ, но это одна из проблем, с которой я столкнулся, пытаясь реализовать «с».

...