> **Источник:** https://python-all.ru/3.1/library/contextlib.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 27.5. `contextlib` – утилиты для контекстов оператора [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with)

Этот модуль предоставляет утилиты для типичных задач, связанных с оператором [`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).

Предоставляемые функции:

#### `contextlib.contextmanager(func)`

Эта функция – [*декоратор*](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__).

Простой пример (это не рекомендуется как реальный способ генерации HTML!):

```python
from contextlib import contextmanager

@contextmanager
def tag(name):
    print("<%s>" % name)
    yield
    print("</%s>" % name)

>>> with tag("h1"):
...    print("foo")
...
<h1>
foo
</h1>
```

Декорируемая функция при вызове должна возвращать [*генератор*](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), если оно есть.

В точке, где генератор выполняет 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).

#### `contextlib.nested(mgr1[, mgr2[, ...]])`

Объединяет несколько менеджеров контекста в один вложенный менеджер контекста.

This 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.

The 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:

```python
from contextlib import nested

with nested(*managers):
    do_something()
```

Note 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.

This 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.

Secondly, 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.

Developers 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.

Устарело с версии 3.1: Оператор with теперь напрямую поддерживает эту функциональность (без запутанных и подверженных ошибкам особенностей).

#### `contextlib.closing(thing)`

Возвращает контекстный менеджер, который закрывает *thing* после завершения блока. По сути эквивалентно следующему:

```python
from contextlib import contextmanager

@contextmanager
def closing(thing):
    try:
        yield thing
    finally:
        thing.close()
```

И позволяет писать код следующим образом:

```python
from contextlib import closing
from urllib.request import urlopen

with closing(urlopen('http://www.python.org')) as page:
    for line in page:
        print(line)
```

без необходимости явно закрывать `page`. Даже если произойдёт ошибка, `page.close()` будет вызван при выходе из блока [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with).

> **См. также**
>
> **[**PEP 0343**](https://python-all.ru/3.1/library/contextlib.html) – оператор «with»**
>
> Спецификация, предыстория и примеры для оператора
>
> [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with)
>
> в Python.
