Overview:
The ‘with’ statement enables the Python code with three things:
- Obtaining a context, without dealing with the internals of creating it
- Working with the context
- Moving on, once done with the context, without the concerns of executing any final steps on the context. (The ‘with’ statement will take care of it)
In a resource management perspective, the above three statements translate into:
- Obtain a resource
- Use the resource
- Leave the block and be rest assured that the resources are cleaned up
with <expression> as <target>:
target.function2()
target.function2()
- There are few more things to the “with” statement - for it to work. A context or a resource or a target, has to be created by a manager class called a context manager or a resource manager.
- Any class that implements the semantics of __entry__() and __exit__() methods is a Context Manager that can work with the ‘with’ statement. Alternately, we can also implement the context management through the decorator @contextmanager and a generator function.
How the context management works through with statement:
- The __enter__() function is called before the contents of the “with” block is executed.
- The __enter__() function after doing whatever steps required as part of the context management, should return the context, which is stored in the target variable. If the target variable is not specified through the as keyword the returned context is stored in a temporary variable.
- The __exit__() function is called after the contents of the 'with' block is executed.
- If any exception is raised during the execution of the code inside the 'with' block still the __exit__() function of the context manager will be called, before the exception is propagated to the outer scopes looking for a handler.
Example:
- In this example the resource obtained is a file object, an instance of the FileIO object. The __enter__() implementation for the FileIO comes from the abstract base class IOBase.
- The method __exit__() is also implemented by the class IOBase.
- In other words, the context manager behavior is built-in to the FileIO class through inheritance and polymorphism.
# Example python program that uses a context manager # and with statement with open('log.txt', 'a') as log: log.write("Writing to log file using the file file object..."); log.write("Done writing to the file");
# By now the file object would have been closed by the context manager # Any writes will now raise an IO exception... log.write("Trying to write"); |
Output:
Traceback (most recent call last): File "with_example.py", line 9, in <module> log.write("Trying to write"); ValueError: I/O operation on closed file. |