Документация Python неофициальный перевод

contextlib.md

161 строк · 10.4 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.2/library/contextlib.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 27.6. [`contextlib`](https://python-all.ru/3.2/library/contextlib.html#module-contextlib) – Утилиты для [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with)-инструкции контекстов89**Исходный код:** [Lib/contextlib.py](https://python-all.ru/src/3.2/Lib/contextlib.py)1011---1213Этот модуль предоставляет утилиты для типичных задач, связанных с оператором [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with). Дополнительную информацию см. также в разделах [*Типы менеджеров контекста*](https://python-all.ru/3.2/library/stdtypes.html#typecontextmanager) и [*Менеджеры контекста оператора with*](https://python-all.ru/3.2/reference/datamodel.html#context-managers).1415Предоставляемые функции:1617#### `@contextlib.contextmanager`1819Эта функция – [*декоратор*](https://python-all.ru/3.2/glossary.html#term-decorator), который можно использовать для определения фабричной функции для менеджеров контекста оператора [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with), без необходимости создавать класс или отдельные методы [`__enter__()`](https://python-all.ru/3.2/reference/datamodel.html#object.__enter__) и [`__exit__()`](https://python-all.ru/3.2/reference/datamodel.html#object.__exit__).2021Простой пример (это не рекомендуется как реальный способ генерации HTML!):2223```python24from contextlib import contextmanager2526@contextmanager27def tag(name):28    print("<%s>" % name)29    yield30    print("</%s>" % name)3132>>> with tag("h1"):33...    print("foo")34...35<h1>36foo37</h1>38```3940Декорируемая функция при вызове должна возвращать [*генератор*](https://python-all.ru/3.2/glossary.html#term-generator)-итератор. Этот итератор должен передать (yield) ровно одно значение, которое будет связано с целями в предложении [`as`](https://python-all.ru/3.2/reference/compound_stmts.html#as) оператора [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with), если оно есть.4142В точке, где генератор выполняет yield, выполняется блок, вложенный в оператор [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with). Затем генератор возобновляется после выхода из блока. Если в блоке возникает необработанное исключение, оно повторно возбуждается внутри генератора в точке, где произошёл yield. Таким образом, можно использовать конструкцию [`try`](https://python-all.ru/3.2/reference/compound_stmts.html#try)...[`except`](https://python-all.ru/3.2/reference/compound_stmts.html#except)...[`finally`](https://python-all.ru/3.2/reference/compound_stmts.html#finally) для перехвата ошибки (если она есть) или для обеспечения выполнения очистки. Если исключение перехватывается лишь для того, чтобы залогировать его или выполнить какое-либо действие (а не подавить его полностью), генератор должен возобновить (reraise) это исключение. В противном случае менеджер контекста-генератор сообщит оператору [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with), что исключение обработано, и выполнение продолжится с оператора, непосредственно следующего за оператором [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with).4344[`contextmanager()`](https://python-all.ru/3.2/library/contextlib.html#contextlib.contextmanager) использует [`ContextDecorator`](https://python-all.ru/3.2/library/contextlib.html#contextlib.ContextDecorator), поэтому создаваемые им менеджеры контекста можно использовать как в качестве декораторов, так и в операторах [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with). При использовании в качестве декоратора новый экземпляр генератора неявно создаётся при каждом вызове функции (это позволяет менеджерам контекста, созданным [`contextmanager()`](https://python-all.ru/3.2/library/contextlib.html#contextlib.contextmanager), которые в противном случае были бы «одноразовыми», удовлетворять требованию, что менеджеры контекста должны поддерживать множественные вызовы, чтобы использоваться в качестве декораторов).4546Изменено в версии 3.2: Использование [`ContextDecorator`](https://python-all.ru/3.2/library/contextlib.html#contextlib.ContextDecorator).4748#### `contextlib.closing(thing)`4950Возвращает контекстный менеджер, который закрывает *thing* после завершения блока. По сути эквивалентно следующему:5152```python53from contextlib import contextmanager5455@contextmanager56def closing(thing):57    try:58        yield thing59    finally:60        thing.close()61```6263И позволяет писать код следующим образом:6465```python66from contextlib import closing67from urllib.request import urlopen6869with closing(urlopen('http://www.python.org')) as page:70    for line in page:71        print(line)72```7374без необходимости явно закрывать `page`. Даже если произойдёт ошибка, `page.close()` будет вызван при выходе из блока [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with).7576#### `class contextlib.ContextDecorator`7778Базовый класс, который позволяет менеджеру контекста также использоваться в качестве декоратора.7980Менеджеры контекста, наследующие от `ContextDecorator`, должны реализовывать `__enter__` и `__exit__` как обычно. `__exit__` сохраняет свою опциональную обработку исключений даже при использовании в качестве декоратора.8182`ContextDecorator` используется [`contextmanager()`](https://python-all.ru/3.2/library/contextlib.html#contextlib.contextmanager), поэтому эта функциональность доступна автоматически.8384Пример `ContextDecorator`:8586```python87from contextlib import ContextDecorator8889class mycontext(ContextDecorator):90    def __enter__(self):91        print('Starting')92        return self9394    def __exit__(self, *exc):95        print('Finishing')96        return False9798>>> @mycontext()99... def function():100...     print('The bit in the middle')101...102>>> function()103Starting104The bit in the middle105Finishing106107>>> with mycontext():108...     print('The bit in the middle')109...110Starting111The bit in the middle112Finishing113```114115Это изменение – всего лишь синтаксический сахар для любой конструкции следующего вида:116117```python118def f():119    with cm():120        # Выполнить действия121```122123`ContextDecorator` позволяет вместо этого написать:124125```python126@cm()127def f():128    # Выполнить действия129```130131Это даёт понять, что `cm` применяется ко всей функции, а не только к её части (и экономия уровня отступа тоже приятна).132133Существующие менеджеры контекста, у которых уже есть базовый класс, могут быть расширены путём использования `ContextDecorator` в качестве примесного класса (mixin class):134135```python136from contextlib import ContextDecorator137138class mycontext(ContextBaseClass, ContextDecorator):139    def __enter__(self):140        return self141142    def __exit__(self, *exc):143        return False144```145146> **Примечание**147>148> Поскольку декорированная функция должна допускать многократный вызов, базовый менеджер контекста должен поддерживать использование в нескольких операторах [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with). Если это не так, то следует использовать исходную конструкцию с явным оператором [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with) внутри функции.149150Новое в версии 3.2.151152> **См. также**153>154> **[**PEP 0343**](https://python-all.ru/3.2/library/contextlib.html) – оператор «with»**155>156> Спецификация, предыстория и примеры для оператора157>158> [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with)159>160> в Python.161