177 lines
5.6 KiB
ReStructuredText
177 lines
5.6 KiB
ReStructuredText
:mod:`contextlib` --- Utilities for :keyword:`with`\ -statement contexts
|
|
========================================================================
|
|
|
|
.. module:: contextlib
|
|
:synopsis: Utilities for with-statement contexts.
|
|
|
|
**Source code:** :source:`Lib/contextlib.py`
|
|
|
|
--------------
|
|
|
|
This module provides utilities for common tasks involving the :keyword:`with`
|
|
statement. For more information see also :ref:`typecontextmanager` and
|
|
:ref:`context-managers`.
|
|
|
|
Functions provided:
|
|
|
|
|
|
.. decorator:: contextmanager
|
|
|
|
This function is a :term:`decorator` that can be used to define a factory
|
|
function for :keyword:`with` statement context managers, without needing to
|
|
create a class or separate :meth:`__enter__` and :meth:`__exit__` methods.
|
|
|
|
A simple example (this is not recommended as a real way of generating HTML!)::
|
|
|
|
from contextlib import contextmanager
|
|
|
|
@contextmanager
|
|
def tag(name):
|
|
print("<%s>" % name)
|
|
yield
|
|
print("</%s>" % name)
|
|
|
|
>>> with tag("h1"):
|
|
... print("foo")
|
|
...
|
|
<h1>
|
|
foo
|
|
</h1>
|
|
|
|
The function being decorated must return a :term:`generator`-iterator when
|
|
called. This iterator must yield exactly one value, which will be bound to
|
|
the targets in the :keyword:`with` statement's :keyword:`as` clause, if any.
|
|
|
|
At the point where the generator yields, the block nested in the :keyword:`with`
|
|
statement is executed. The generator is then resumed after the block is exited.
|
|
If an unhandled exception occurs in the block, it is reraised inside the
|
|
generator at the point where the yield occurred. Thus, you can use a
|
|
:keyword:`try`...\ :keyword:`except`...\ :keyword:`finally` statement to trap
|
|
the error (if any), or ensure that some cleanup takes place. If an exception is
|
|
trapped merely in order to log it or to perform some action (rather than to
|
|
suppress it entirely), the generator must reraise that exception. Otherwise the
|
|
generator context manager will indicate to the :keyword:`with` statement that
|
|
the exception has been handled, and execution will resume with the statement
|
|
immediately following the :keyword:`with` statement.
|
|
|
|
:func:`contextmanager` uses :class:`ContextDecorator` so the context managers
|
|
it creates can be used as decorators as well as in :keyword:`with` statements.
|
|
When used as a decorator, a new generator instance is implicitly created on
|
|
each function call (this allows the otherwise "one-shot" context managers
|
|
created by :func:`contextmanager` to meet the requirement that context
|
|
managers support multiple invocations in order to be used as decorators).
|
|
|
|
.. versionchanged:: 3.2
|
|
Use of :class:`ContextDecorator`.
|
|
|
|
|
|
.. function:: closing(thing)
|
|
|
|
Return a context manager that closes *thing* upon completion of the block. This
|
|
is basically equivalent to::
|
|
|
|
from contextlib import contextmanager
|
|
|
|
@contextmanager
|
|
def closing(thing):
|
|
try:
|
|
yield thing
|
|
finally:
|
|
thing.close()
|
|
|
|
And lets you write code like this::
|
|
|
|
from contextlib import closing
|
|
from urllib.request import urlopen
|
|
|
|
with closing(urlopen('http://www.python.org')) as page:
|
|
for line in page:
|
|
print(line)
|
|
|
|
without needing to explicitly close ``page``. Even if an error occurs,
|
|
``page.close()`` will be called when the :keyword:`with` block is exited.
|
|
|
|
|
|
.. class:: ContextDecorator()
|
|
|
|
A base class that enables a context manager to also be used as a decorator.
|
|
|
|
Context managers inheriting from ``ContextDecorator`` have to implement
|
|
``__enter__`` and ``__exit__`` as normal. ``__exit__`` retains its optional
|
|
exception handling even when used as a decorator.
|
|
|
|
``ContextDecorator`` is used by :func:`contextmanager`, so you get this
|
|
functionality automatically.
|
|
|
|
Example of ``ContextDecorator``::
|
|
|
|
from contextlib import ContextDecorator
|
|
|
|
class mycontext(ContextDecorator):
|
|
def __enter__(self):
|
|
print('Starting')
|
|
return self
|
|
|
|
def __exit__(self, *exc):
|
|
print('Finishing')
|
|
return False
|
|
|
|
>>> @mycontext()
|
|
... def function():
|
|
... print('The bit in the middle')
|
|
...
|
|
>>> function()
|
|
Starting
|
|
The bit in the middle
|
|
Finishing
|
|
|
|
>>> with mycontext():
|
|
... print('The bit in the middle')
|
|
...
|
|
Starting
|
|
The bit in the middle
|
|
Finishing
|
|
|
|
This change is just syntactic sugar for any construct of the following form::
|
|
|
|
def f():
|
|
with cm():
|
|
# Do stuff
|
|
|
|
``ContextDecorator`` lets you instead write::
|
|
|
|
@cm()
|
|
def f():
|
|
# Do stuff
|
|
|
|
It makes it clear that the ``cm`` applies to the whole function, rather than
|
|
just a piece of it (and saving an indentation level is nice, too).
|
|
|
|
Existing context managers that already have a base class can be extended by
|
|
using ``ContextDecorator`` as a mixin class::
|
|
|
|
from contextlib import ContextDecorator
|
|
|
|
class mycontext(ContextBaseClass, ContextDecorator):
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *exc):
|
|
return False
|
|
|
|
.. note::
|
|
As the decorated function must be able to be called multiple times, the
|
|
underlying context manager must support use in multiple :keyword:`with`
|
|
statements. If this is not the case, then the original construct with the
|
|
explicit :keyword:`with` statement inside the function should be used.
|
|
|
|
.. versionadded:: 3.2
|
|
|
|
|
|
.. seealso::
|
|
|
|
:pep:`0343` - The "with" statement
|
|
The specification, background, and examples for the Python :keyword:`with`
|
|
statement.
|
|
|