contextlib.md
1> **Источник:** https://python-all.ru/3.1/library/contextlib.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 27.5. `contextlib` – утилиты для контекстов оператора [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with)89Этот модуль предоставляет утилиты для типичных задач, связанных с оператором [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with). Дополнительную информацию см. также в разделах [*Типы менеджеров контекста*](https://python-all.ru/3.1/library/stdtypes.html#typecontextmanager) и [*Менеджеры контекста оператора with*](https://python-all.ru/3.1/reference/datamodel.html#context-managers).1011Предоставляемые функции:1213#### `contextlib.contextmanager(func)`1415Эта функция – [*декоратор*](https://python-all.ru/3.1/glossary.html#term-decorator), который можно использовать для определения фабричной функции для менеджеров контекста оператора [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with), без необходимости создавать класс или отдельные методы [`__enter__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__enter__) и [`__exit__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__exit__).1617Простой пример (это не рекомендуется как реальный способ генерации HTML!):1819```python20from contextlib import contextmanager2122@contextmanager23def tag(name):24 print("<%s>" % name)25 yield26 print("</%s>" % name)2728>>> with tag("h1"):29... print("foo")30...31<h1>32foo33</h1>34```3536Декорируемая функция при вызове должна возвращать [*генератор*](https://python-all.ru/3.1/glossary.html#term-generator)-итератор. Этот итератор должен передать (yield) ровно одно значение, которое будет связано с целями в предложении [`as`](https://python-all.ru/3.1/reference/compound_stmts.html#as) оператора [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with), если оно есть.3738В точке, где генератор выполняет yield, выполняется блок, вложенный в оператор [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with). Затем генератор возобновляется после выхода из блока. Если в блоке возникает необработанное исключение, оно повторно возбуждается внутри генератора в точке, где произошёл yield. Таким образом, можно использовать конструкцию [`try`](https://python-all.ru/3.1/reference/compound_stmts.html#try)...[`except`](https://python-all.ru/3.1/reference/compound_stmts.html#except)...[`finally`](https://python-all.ru/3.1/reference/compound_stmts.html#finally) для перехвата ошибки (если она есть) или для обеспечения выполнения очистки. Если исключение перехватывается лишь для того, чтобы залогировать его или выполнить какое-либо действие (а не подавить его полностью), генератор должен возобновить (reraise) это исключение. В противном случае менеджер контекста-генератор сообщит оператору [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with), что исключение обработано, и выполнение продолжится с оператора, непосредственно следующего за оператором [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with).3940#### `contextlib.nested(mgr1[, mgr2[, ...]])`4142Объединяет несколько менеджеров контекста в один вложенный менеджер контекста.4344This function has been deprecated in favour of the multiple manager form of the [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with) statement.4546The one advantage of this function over the multiple manager form of the [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with) statement is that argument unpacking allows it to be used with a variable number of context managers as follows:4748```python49from contextlib import nested5051with nested(*managers):52 do_something()53```5455Note that if the [`__exit__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__exit__) method of one of the nested context managers indicates an exception should be suppressed, no exception information will be passed to any remaining outer context managers. Similarly, if the [`__exit__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__exit__) method of one of the nested managers raises an exception, any previous exception state will be lost; the new exception will be passed to the [`__exit__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__exit__) methods of any remaining outer context managers. In general, [`__exit__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__exit__) methods should avoid raising exceptions, and in particular they should not re-raise a passed-in exception.5657This function has two major quirks that have led to it being deprecated. Firstly, as the context managers are all constructed before the function is invoked, the [`__new__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__new__) and [`__init__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__init__) methods of the inner context managers are not actually covered by the scope of the outer context managers. That means, for example, that using [`nested()`](https://python-all.ru/3.1/library/contextlib.html#contextlib.nested) to open two files is a programming error as the first file will not be closed promptly if an exception is thrown when opening the second file.5859Secondly, if the [`__enter__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__enter__) method of one of the inner context managers raises an exception that is caught and suppressed by the [`__exit__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__exit__) method of one of the outer context managers, this construct will raise [`RuntimeError`](https://python-all.ru/3.1/library/exceptions.html#RuntimeError) rather than skipping the body of the [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with) statement.6061Developers that need to support nesting of a variable number of context managers can either use the [`warnings`](https://python-all.ru/3.1/library/warnings.html#module-warnings) module to suppress the DeprecationWarning raised by this function or else use this function as a model for an application specific implementation.6263Устарело с версии 3.1: Оператор with теперь напрямую поддерживает эту функциональность (без запутанных и подверженных ошибкам особенностей).6465#### `contextlib.closing(thing)`6667Возвращает контекстный менеджер, который закрывает *thing* после завершения блока. По сути эквивалентно следующему:6869```python70from contextlib import contextmanager7172@contextmanager73def closing(thing):74 try:75 yield thing76 finally:77 thing.close()78```7980И позволяет писать код следующим образом:8182```python83from contextlib import closing84from urllib.request import urlopen8586with closing(urlopen('http://www.python.org')) as page:87 for line in page:88 print(line)89```9091без необходимости явно закрывать `page`. Даже если произойдёт ошибка, `page.close()` будет вызван при выходе из блока [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with).9293> **См. также**94>95> **[**PEP 0343**](https://python-all.ru/3.1/library/contextlib.html) – оператор «with»**96>97> Спецификация, предыстория и примеры для оператора98>99> [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with)100>101> в Python.102