Understand the With statement in Python

  • 2020-04-02 14:34:01
  • OfStack

What is the With statement?

There are some tasks that may need to be set up in advance and cleaned up afterwards. Python's with statement provides a very convenient way to handle this scenario. A good example is file handling, where you need to get a file handle, read data from the file, and then close the file handle.

If the with statement is not used, the code is as follows:


file = open("/tmp/foo.txt")
data = file.read()
file.close()

There are two problems. One is that you may forget to close the file handle. Second, the file read data abnormal, did not carry out any processing. Here is an enhanced version of handling exceptions:


file = open("/tmp/foo.txt")
try:
    data = file.read()
finally:
    file.close()

This code works fine, but it's too verbose. Now is the time for with to show what he can do. In addition to having a more elegant syntax, with also handles exceptions well from context. Here is the code for the with version:


with open("/tmp /foo.txt") as file:
    data = file.read()

How does with work?

This seems like a lot of magic, but it's not just magic. Python's handling of with is clever. The basic idea is with the object of the desired value must have a __enter__ () method, a __exit__ () method.

After the statement following with is evaluated, the return object's return value of this method is assigned to the variable following as. After all the blocks following with have been executed, the previous method of returning the object is called with s/s ().

The following example illustrates how with works:


#!/usr/bin/env python
# with_example01.py class Sample:
    def __enter__(self):
        print "In __enter__()"
        return "Foo"     def __exit__(self, type, value, trace):
        print "In __exit__()"
def get_sample():
    return Sample()
with get_sample() as sample:
    print "sample:", sample

Line of code, the output is as follows


bash-3.2$ ./with_example01.py
In __enter__()
sample: Foo
In __exit__()

As you can see,

The s/s method is executed

The value returned by the method - 'Foo' in this case, assign the variable 'sample'
Execute the block of code and print the value of the variable "sample" as "Foo"

S/s method is called

What's really powerful about with is that it can handle exceptions. You may have noticed that the Sample class's s/s method has three arguments - val, type and trace. These parameters are useful in exception handling. Let's change the code to see how it works.


#!/usr/bin/env python
# with_example02.py
class Sample:
    def __enter__(self):
        return self     def __exit__(self, type, value, trace):
        print "type:", type
        print "value:", value
        print "trace:", trace     def do_something(self):
        bar = 1/0
        return bar + 10 with Sample() as sample:
    sample.do_something()

In this example, get_sample() after with becomes Sample(). This does not matter, as long as the object returned by the statement following with has the method of s/s/s/s/s/s/s/s. In this case, the s/s method of Sample() returns the newly created Sample object and assigns the value to the variable Sample.

After code execution:


bash-3.2$ ./with_example02.py
type: <type 'exceptions.ZeroDivisionError'>
value: integer division or modulo by zero
trace: <traceback object at 0x1004a8128>
Traceback (most recent call last):
  File "./with_example02.py", line 19, in <module>
    sample.do_somet hing()
  File "./with_example02.py", line 15, in do_something
    bar = 1/0
ZeroDivisionError: integer division or modulo by zero

In fact, with any exceptions thrown by the block after with, the method is executed. As shown in the example, when an exception is thrown, the associated type, value, and stack trace are passed to the method with s/s (), so the thrown ZeroDivisionError exception is printed. While developing the library, clean up the resources, close the files, etc., can be placed in the s/s method.

Therefore, Python's with statement is an effective mechanism for simplifying code and making it easier to clean up when exceptions are generated.

Sample code can be found on Github.


Related articles: