Jun 01, 2021 Article blog
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?
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.
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.
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.