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

contextlib.md

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

1> **Источник:** https://python-all.ru/2.7/library/contextlib.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 28.7. [`contextlib`](https://python-all.ru/2.7/library/contextlib.html#module-contextlib) – Утилиты для контекстов оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with)89Новое в версии 2.5.1011**Исходный код:** [Lib/contextlib.py](https://python-all.ru/src/2.7/Lib/contextlib.py)1213---1415Этот модуль предоставляет утилиты для типовых задач, связанных с оператором [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with). Для получения дополнительной информации см. также [Типы менеджеров контекста](https://python-all.ru/2.7/library/stdtypes.html#typecontextmanager) и [Менеджеры контекста оператора with](https://python-all.ru/2.7/reference/datamodel.html#context-managers).1617Предоставляемые функции:1819#### `contextlib.contextmanager(func)`2021Эта функция – [декоратор](https://python-all.ru/2.7/glossary.html#term-decorator), который можно использовать для определения фабричной функции для контекстных менеджеров оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with), без необходимости создавать класс или отдельные методы [`__enter__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__enter__) и [`__exit__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__exit__).2223Хотя многие объекты изначально поддерживают использование в with-выражениях, иногда требуется управлять ресурсом, который сам по себе не является менеджером контекста, и не реализует метод `close()` для использования с `contextlib.closing`2425Абстрактным примером может служить следующий код для обеспечения корректного управления ресурсами:2627```python28from contextlib import contextmanager2930@contextmanager31def managed_resource(*args, **kwds):32    # Код для получения ресурса, например:33    resource = acquire_resource(*args, **kwds)34    try:35        yield resource36    finally:37        # Код для освобождения ресурса, например:38        release_resource(resource)3940>>> with managed_resource(timeout=3600) as resource:41...     # Ресурс освобождается в конце этого блока,42...     # даже если код в блоке вызывает исключение43```4445Декорируемая функция при вызове должна возвращать [генератор](https://python-all.ru/2.7/glossary.html#term-generator)-итератор. Этот итератор должен возвращать ровно одно значение, которое будет связано с целями в предложении [`as`](https://python-all.ru/2.7/reference/compound_stmts.html#as) оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with), если таковые имеются.4647В момент, где генератор делает yield, выполняется блок, вложенный в оператор [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with). Затем генератор возобновляется после выхода из блока. Если в блоке возникает необработанное исключение, оно повторно возбуждается внутри генератора в точке, где произошел yield. Таким образом, можно использовать оператор [`try`](https://python-all.ru/2.7/reference/compound_stmts.html#try)…[`except`](https://python-all.ru/2.7/reference/compound_stmts.html#except)…[`finally`](https://python-all.ru/2.7/reference/compound_stmts.html#finally) для перехвата ошибки (если есть) или для выполнения очистки. Если исключение перехватывается только для того, чтобы зарегистрировать его или выполнить какое-либо действие (а не подавить полностью), генератор должен повторно возбудить это исключение. В противном случае контекстный менеджер генератора сообщит оператору [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with), что исключение обработано, и выполнение продолжится с оператора, следующего сразу за оператором [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with).4849#### `contextlib.nested(mgr1[, mgr2[, ...]])`5051Объединяет несколько менеджеров контекста в один вложенный менеджер контекста.5253Эта функция устарела в пользу формы с несколькими менеджерами оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with).5455Единственное преимущество этой функции перед формой с несколькими менеджерами оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with) заключается в том, что распаковка аргументов позволяет использовать её с переменным числом менеджеров контекста следующим образом:5657```python58from contextlib import nested5960with nested(*managers):61    do_something()62```6364Обратите внимание: если метод [`__exit__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__exit__) одного из вложенных менеджеров контекста указывает, что исключение должно быть подавлено, информация об исключении не будет передана ни одному из оставшихся внешних менеджеров контекста. Аналогично, если метод [`__exit__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__exit__) одного из вложенных менеджеров вызывает исключение, любое предыдущее состояние исключения будет потеряно; новое исключение будет передано методам [`__exit__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__exit__) оставшихся внешних менеджеров контекста. В общем случае методы [`__exit__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__exit__) должны избегать возбуждения исключений, и в особенности они не должны повторно возбуждать переданное исключение.6566У этой функции есть два существенных недостатка, из-за которых она была объявлена устаревшей. Во-первых, поскольку все менеджеры контекста создаются до вызова функции, методы [`__new__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__new__) и [`__init__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__init__) внутренних менеджеров контекста на самом деле не находятся в области действия внешних менеджеров контекста. Это означает, например, что использование [`nested()`](https://python-all.ru/2.7/library/contextlib.html#contextlib.nested) для открытия двух файлов является ошибкой программирования, так как первый файл не будет своевременно закрыт, если при открытии второго возникнет исключение.6768Во-вторых, если метод [`__enter__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__enter__) одного из внутренних менеджеров контекста вызывает исключение, которое перехватывается и подавляется методом [`__exit__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__exit__) одного из внешних менеджеров контекста, то данная конструкция возбудит [`RuntimeError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.RuntimeError) вместо того, чтобы пропустить тело оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with).6970Разработчикам, которым требуется поддержка вложения переменного числа менеджеров контекста, можно либо использовать модуль [`warnings`](https://python-all.ru/2.7/library/warnings.html#module-warnings) для подавления DeprecationWarning, возбуждаемого этой функцией, либо взять эту функцию за образец для реализации в своём приложении.7172Устарело с версии 2.7: Оператор with теперь напрямую поддерживает эту функциональность (без сбивающих с толку чреватых ошибками странностей).7374#### `contextlib.closing(thing)`7576Возвращает контекстный менеджер, который закрывает *thing* после завершения блока. По сути эквивалентно следующему:7778```python79from contextlib import contextmanager8081@contextmanager82def closing(thing):83    try:84        yield thing85    finally:86        thing.close()87```8889И позволяет писать код следующим образом:9091```python92from contextlib import closing93import urllib9495with closing(urllib.urlopen('http://www.python.org')) as page:96    for line in page:97        print line98```99100без необходимости явно закрывать `page`. Даже если произойдет ошибка, `page.close()` будет вызван при выходе из блока [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with).101102> **См. также**103>104> **[**PEP 343**](https://python-all.ru/2.7/library/contextlib.html) – Оператор «with»**105>106> Спецификация, предыстория и примеры для инструкции [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with) в Python.107