Context Manager
Conception
Context managers can be used for more than just opening and closing files.
If we think about it there are two phases to a context manager:
when the
withstatement is executing: we enter the contextwhen the
withblock is done: we exit the context
We can create our own context manager using a class that implements an __enter__ method which is executed when we enter the context, and an __exit__ method that is executed when we exit the context.
There is a general pattern that context managers can help us deal with:
Open - Close
Lock - Release
Change - Reset
Enter - Exit
Start - Stop
The __enter__ method is quite straightforward. It can (but does not have to) return one or more objects we then use inside the with block.
The __exit__ method however is slightly more complicated.
It needs to return a boolean True/False. This indicates to Python whether to suppress any errors that occurred in the with block. As we saw with files, that was not the case - i.e. it returns a False
If an error does occur in the with block, the error information is passed to the
__exit__method - so it needs three things: the exception type, the exception value and the traceback. If no error occured, then those values will simply be None.
Let's go ahead and create a context manager:
We can even cause an exception inside the with block:
We can change that by returning True from the __exit__ method:
Notice that the obj we obtained from the context manager, still exists in our scope after the with statement.The with statement does not have its own local scope - it's not a function! However, the context manager could manipulate the object returned by the context manager:
We still have access to res, but it's internal state was changed by the resource manager's __exit__ method.Although we already have a context manager for files built-in to Python, let's go ahead and write our own anyways - good practice.
Note that the __enter__ method can return anything, including the context manager itself.
If we wanted to, we could re-write our file context manager this way:
Working with Iterator
Additional Use
common patterns we can implement with context managers:
Open - Close
Change - Reset
Start - Stop
Decimal Contexts
If we create a decimal object, then it will use those settings.We can certainly change the properties of that global context:
Suppose now that we just want to temporarily change something in the context - we would have to do something like this:
Of course, this is kind of a pain to have to store the current value, set it to something new, and then remember to set it back to it's original value.
How about writing a context manager to do that seamlessly for us:
In fact, the decimal class already has a context manager, and it's way better than ours, because we can set not only the precision, but anything else we want:
Timing a with block
Decorator
Fortunately the standard library has already though of this - in fact that was one of the critical goals of Python's context managers - the ability to create context managers using generator functions (see PEP 343).
`Let's implement a timer.
Last updated
Was this helpful?