Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

All you know is with, what about the with who?


Jun 01, 2021 Article blog


Table of contents


During your long programming development, you've certainly seen or used the following code:

with open("test.txt", "r", encoding="utf-8") as f:
    s = f.readlines()

Some people will know why, but more people don't know why. I just think everyone else writes like that, and I write with it.

At the same time, many people who know why just know it but don't know why: the with statement automatically closes open file objects for us. But what mechanism does this work?

1. With and exception handling

We know that if you don't use with statement, it's a normal process to read and write a file: open the file, manipulate the file, close the file. The Python code is expressed as follows:

f = open("test.txt", "r", encoding="utf-8")
s = f.readlines()
f.close()

Under normal circumstances, it doesn't seem like a problem to write like this.

Next, let's create a little "surprise" by changing the pattern specified when the file object is opened from "r" to "w".

f = open("test.txt", "w", encoding="utf-8")
s = f.readlines()
f.close()

At this point, when the program executes to read the contents of the file on line 2, an error is thrown:

Traceback (most recent call last):
  File "test_with.py", line 2, in <module>
    s = f.readlines()
io.UnsupportedOperation: not readable

And then...... A terrible situation happened.

Python exits with an unprocessed exception, leaving the code after line 2 unexemented, so f.close() never has a chance to execute again. A lonely ghost-like open file object is so a person floating in the sea of memory, no one knows who he is, where he came from, where he is going.

In this way, every time an exception is thrown, such a wandering object will be produced. Over time, the sea of memory has naturally been transformed into a land of vagrants, and others want to come to no end.

In the final analysis, we find that the key to this problem is the "open-operation-close" file in this flow operation, there is the possibility of throwing exceptions.

So we thought of using the big killer that Python provided us with to deal with these anomalies: try-catch

Transform the previous code with exception handling:

try:
    f = open("test.txt", "a", encoding="utf-8")
    s = f.readlines()
except:
    print("出现异常")
finally:
    f.close()

This ensures that open files are closed with additional finally statements, regardless of whether the file operation throws an exception or not. This avoids the problem of resource leakage caused by constant resource consumption.

In fact, the with statement provides us with a try-catch-finally encapsulation.

Programming, which seems to be just a casual with, has in fact implicitly ensured an exception handling mechanism similar to the code above.

2. Context Manager

For with to take effect, it needs to act on a context manager

Hold on, what exactly is a context manager?

A long story short is the object that implements __enter__ and __exit__ methods.

Both methods are loaded for use before entering a runtime context. When you enter this runtime context, __enter__ method is called, and the __exit__ method is called before exiting the context.

The runtime context here can simply be understood as a scope of code that provides some special configuration.

When we use the code with open("test.txt", "r", encoding="utf-8") as f Python first evaluates open("test.txt", "r", encoding="utf-8") to get a context manager.

What's special here is that Python Chinese object itself is a context manager, so we can use open function as an expression for evaluation.

The __enter__ method is then called and the returned object is bound to the identifier f that we specify. The __enter__ of the file object returns the file object itself, so the code binds the open test .txt file object to the identifier f

Follows the contents of the block that executes the with statement.

__exit__ and exit the with statement block.

Based on the above, we can also construct a context manager ourselves (note that the parameters of the two feature methods should be consistent with the protocol):

class testContextManager:
    def __enter__(self):
        print("进入运行时上下文,调用__enter__方法")


    def __exit__(self, exc_type, exc_value, traceback):
        print("退出运行时上下文,调用__exit__方法")




with testContextManager() as o:
    pass

Output:

进入运行时上下文,调用__enter__方法
退出运行时上下文,调用__exit__方法

The with statement replaces cumbersome exception handling statements precisely because the context manager implements __enter__ and __exit__ methods in accordance with the protocol, and the with statement ensures that __exit__ method can be executed in the event of an exception and exit the relevant runtime context.

In this method, we can do some of the necessary cleanup work.

summary

In this article, we explained the internal logic of the with statement and tried to implement a custom context manager. I believe you have a deeper understanding of how with works.

The with statement can be used not only for reading and writing files, but also for automatic acquisition and release of locks, saving and restoring global states, and so on. More practical ways to explore.

Source: Public Number -- Python Technology Author: Pieson Sauce

Above is W3Cschool编程狮 about you only know the with, then the with who? Related to the introduction, I hope to help you.