Реализация использования 'with object() как f' в пользовательском классе в python
Мне нужно открыть файл-подобный объект в python (это последовательное соединение через /dev/ ), а затем закрыть его. Это делается несколько раз в нескольких методах моего класса. Как я это делал, это открытие файла в конструкторе, а затем его закрытие в деструкторе. Я получаю странные ошибки, хотя, и я думаю, что это связано с сборщиком мусора и т.д., Я до сих пор не привык к тому, что точно не знаю, когда мои объекты удаляются =\
Причина, по которой я это делаю, заключается в том, что я должен использовать tcsetattr
с кучей параметров каждый раз, когда я его открываю, и это раздражает, делая все это повсюду. Поэтому я хочу реализовать внутренний класс для обработки всего этого, чтобы я мог его использовать.
with Meter('/dev/ttyS2') as m:
Я смотрел онлайн, и я не мог найти действительно хороший ответ о синтаксисе with
. Я видел, что он использует методы __enter__(self)
и __exit(self)__
. Но все, что мне нужно, реализовать эти методы, и я могу использовать синтаксис с синтаксисом? Или есть еще что-нибудь?
Есть ли пример о том, как это сделать или какую-нибудь документацию о том, как он реализован в объектах файлов, на которые я могу смотреть?
Ответы
Ответ 1
Эти методы в значительной степени необходимы для создания объекта с помощью оператора with
.
В __enter__
вам нужно вернуть объект файла после его открытия и настройки.
В __exit__
вам нужно закрыть файл. Код для записи в него будет находиться в теге with
.
class Meter():
def __init__(self, dev):
self.dev = dev
def __enter__(self):
#ttysetattr etc goes here before opening and returning the file object
self.fd = open(self.dev, MODE)
return self.fd
def __exit__(self, type, value, traceback):
#Exception handling here
close(self.fd)
meter = Meter('dev/tty0')
with meter as m:
#here you work with the file object.
m.read()
Ответ 2
Самый простой способ - использовать стандартный библиотечный модуль Python contextlib:
import contextlib
@contextlib.contextmanager
def themeter(name):
theobj = Meter(name)
yield theobj
theobj.close() # or whatever you need to do at exit
Это не делает Meter
себя менеджером контекста (и поэтому неинвазивным для этого класса), а скорее "украшает" его (не в смысле синтаксиса "декоратора" Python ", а почти, но не совсем, в смысле шаблона проектирования декоратора;-) с помощью функции factory themeter
, которая является менеджером контекста (который декодер contextlib.contextmanager
строит из созданной вами функции генератора" single-yield
") - это делает его таким образом намного легче отделить условие ввода и выхода, избегает вложенности и .
Ответ 3
Первый хит Google (для меня) достаточно просто объясняет:
http://effbot.org/zone/python-with-statement.htm
и PEP объясняет это более точно (но также более подробно):
http://www.python.org/dev/peps/pep-0343/