The Context Management Protocol

Although some built-in types come with context managers, we can also write new ones of our own. To implement context managers, classes use special methods that fall into the operator overloading category to tap into the with statement. The interface expected of objects used in with statements is somewhat complex, and most programmers only need to know how to use existing context managers. For tool builders who might want to write new application-specific context managers, though, let's take a quick look at what's involved.

Here's how the with statement actually works:

1. The expression is evaluated, resulting in an object known as a context manager that must have_enter_and_exit__methods.

2. The context manager's_enter_method is called. The value it returns is assigned to the variable in the as clause if present, or simply discarded otherwise.

3. The code in the nested with block is executed.

4. If the with block raises an exception, the__exit_(type, value, traceback) method is called with the exception details. Note that these are the same values returned by sys.exc_info, described in the Python manuals and later in this part of the book. If this method returns a false value, the exception is reraised; otherwise, the exception is terminated. The exception should normally be reraised so that it is propagated outside the with statement.

5. If the with block does not raise an exception, the_exit_method is still called, but its type, value, and traceback arguments are all passed in as None.

Let's look at a quick demo of the protocol in action. The following defines a context manager object that traces the entry and exit of the with block in any with statement it is used for:

class TraceBlock:

def message(self, arg): print('running', arg)

print('starting with block') return self def _exit_(self, exc_type, exc_value, exc_tb):

if exc_type is None:

print('exited normally\n') else:

print('raise an exception!', exc_type)

return False # Propagate with TraceBlock() as action: action.message('test 1') print('reached')

with TraceBlock() as action: action.message('test 2') raise TypeError print('not reached')

Notice that this class's __exit__ method returns False to propagate the exception; deleting the return statement would have the same effect, as the default None return value of functions is False by definition. Also notice that the_enter_method returns self as the object to assign to the as variable; in other use cases, this might return a completely different object instead.

When run, the context manager traces the entry and exit of the with statement block with its_enter_and_exit_methods. Here's the script in action being run under

Python 3.0 (it runs in 2.6, too, but prints some extra tuple parentheses):

% python withas.py starting with block running test 1 reached exited normally starting with block running test 2

raise an exception! <class 'TypeError'> Traceback (most recent call last):

File "withas.py", line 20, in <module> raise TypeError TypeError

Context managers are somewhat advanced devices for tool builders, so we'll skip additional details here (see Python's standard manuals for the full story—for example, there's a new contextlib standard module that provides additional tools for coding context managers). For simpler purposes, the try/finally statement provides sufficient support for termination-time activities.

* > In the upcoming Python 3.1 release, the with statement may also specify multiple (sometimes referred to as "nested") context managers with new ' ^ I $ comma syntax. In the following, for example, both files' exit actions are automatically run when the statement block exits, regardless of exception outcomes:

with open('data') as fin, open('res', 'w') as fout: for line in fin:

if 'some key' in line: fout.write(line)

Any number of context manager items may be listed, and multiple items work the same as nested with statements. In general, the 3.1 (and later) code:

is equivalent to the following, which works in 3.1, 3.0, and 2.6:

See Python 3.1 release notes for additional details.

0 0

Post a comment

  • Receive news updates via email from this site