diff options
Diffstat (limited to 'Doc/library/contextlib.rst')
-rw-r--r-- | Doc/library/contextlib.rst | 126 |
1 files changed, 78 insertions, 48 deletions
diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index ca37f0f..a35ea56 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -4,6 +4,9 @@ .. 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 @@ -12,7 +15,7 @@ statement. For more information see also :ref:`typecontextmanager` and Functions provided: -.. function:: contextmanager(func) +.. 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 @@ -51,54 +54,11 @@ Functions provided: the exception has been handled, and execution will resume with the statement immediately following the :keyword:`with` statement. + contextmanager uses :class:`ContextDecorator` so the context managers it + creates can be used as decorators as well as in :keyword:`with` statements. -.. function:: nested(mgr1[, mgr2[, ...]]) - - Combine multiple context managers into a single nested context manager. - - This function has been deprecated in favour of the multiple manager form - of the :keyword:`with` statement. - - The one advantage of this function over the multiple manager form of the - :keyword:`with` statement is that argument unpacking allows it to be - used with a variable number of context managers as follows:: - - from contextlib import nested - - with nested(*managers): - do_something() - - Note that if the :meth:`__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 - :meth:`__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 - :meth:`__exit__` methods of any remaining outer context managers. In general, - :meth:`__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 - :meth:`__new__` and :meth:`__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 :func:`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 :meth:`__enter__` method of one of the inner context managers - raises an exception that is caught and suppressed by the :meth:`__exit__` method - of one of the outer context managers, this construct will raise - :exc:`RuntimeError` rather than skipping the body of the :keyword:`with` - statement. - - Developers that need to support nesting of a variable number of context managers - can either use the :mod:`warnings` module to suppress the DeprecationWarning - raised by this function or else use this function as a model for an application - specific implementation. - - .. deprecated:: 3.1 - The with-statement now supports this functionality directly (without the - confusing error prone quirks). + .. versionchanged:: 3.2 + Use of :class:`ContextDecorator`. .. function:: closing(thing) @@ -128,6 +88,76 @@ Functions provided: ``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 + + .. versionadded:: 3.2 + + .. seealso:: :pep:`0343` - The "with" statement |