Table of contents
with statement
In our daily use scenarios, we often operate some resources, such as file objects, database connections, socket connections, etc. After the resource operation is completed, regardless of whether the operation is successful or not, the most important thing is to close the resource, otherwise the resource is opened too much If it is not closed, the program will report an error. Taking file operations as an example, we usually write like this:
f = open('file.txt', 'w')
try:
f.write("Hello")
finally:
f.close()
But since the close method is a necessary operation, there is no need to call it explicitly, so Python provides us with a more elegant way, using the with statement:
with open('file.txt', 'w') as f:
f.write("Hello")
After exiting the code block under the with statement, the f object will automatically execute its own close method to release resources, which is concise and elegant.
Context manager principle
A context manager is actually an object that implements __enter__
the and __exit__
method internally.
When we use the with syntax:
__enter__()
Method: return a value, which can be assigned to the object behind as, such as f in the above;
__exit__()
Method: This method will be executed when the with statement exits or an exception is sent.
1. __enter__
Method description
The method of the context manager __enter__
can have a return value, which returns None by default. This return value is assigned to the variable behind it through the as in with...as..., so with EXPR as VAR is to assign the return value of the EXPR object __enter__
method to VAR.
Of course, with...as...
it is not a fixed combination, and it is also possible to use it alone. The method with...
of the context manager is still executed normally, but the return value is not assigned to a variable, and the code block below with cannot use this return value.__enter__
2. __exit__
Method description
The method of the context manager __exit__
receives 3 parameters exc_type
, exc_val
, exc_tb
, if an exception e occurs in the code block BLOCK and exits, these 3 parameters are type(e)
, str(e)
, e.__traceback__
, otherwise they are all None.
The same __exit__
method can also have a return value. This return value should be a Boolean type True or False, and the default is None (that is, False). If it is False, an exception will be thrown, and the user needs to perform exception handling. If True, means ignore the exception.
A context manager is typically used as follows:
with EXPR as VAR:
BLOCK
The execution process of the above code is equivalent to:
ContextManager = EXPR
VAR = ContextManager.__enter__()
try:
BLOCK
finally:
ContextManager.__exit__()
The f object defines its own close method inside its __exit__
method, and realizes that the code block BLOCK automatically closes itself after execution.
custom context manager
Below we define a file class that implements __enter__
and __exit__
two methods internally:
class File:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print("进入")
self.f = open(self.filename, self.mode)
return self.f
def __exit__(self, exc_type=None, exc_val=None, exc_tbs=None):
print("退出")
self.f.close()
At this time, the File class is a context manager
We use the File class to write to the file through the with statement and the try/finally statement respectively
Execute through the with statement:
with File('file.txt', 'w') as f:
print("正在写入...")
f.write('Hello')
Console output:
进入
正在写入...
退出
And got a file.txt file written Hello
Execute with a try/finally statement:
ContextManager = File('file.txt', 'w')
VAR = ContextManager .__enter__()
try:
print("正在写入...")
VAR.write('Hello')
finally:
ContextManager.__exit__()
Console output:
进入
正在写入...
退出
And got a file.txt file written Hello
The output of the two is consistent, so it is verified that the equivalence relationship of the second execution process is correct.
contextmanager decorator
Python also provides a contextmanager decorator that allows users to define a generator as a context manager. This decorator divides the code in the generator into two parts through the yield statement. The code before yield is a method, and the code after yield is __enter__
a __exit__
method , the return value of yield is __enter__
the return value of the method, which is used to assign to the variable after as.
Below we also implement a context manager for files through the contextmanager decorator:
from contextlib import contextmanager
@contextmanager
def open_file(filename, mode):
print('进入')
f = open(filename, mode)
try:
yield f
finally:
print('退出')
f.close()
Note: The use of try/finally here is to ensure that even if an exception occurs during the yield process, the file can be closed normally. Of course, exceptions can also be handled here, just use try/except/finally.
Execute through the with statement:
with open_file('file.txt', 'w') as f:
print("正在写入...")
f.write('Hello')
The execution result is consistent with the execution result of the previous context manager, indicating that the contextmanager decorator can also define a context manager.
reference:
https://mp.weixin.qq.com/s?__biz=MzAxMjUyNDQ5OA==&mid=2653557641&idx=2&sn=fb26d2f9a4b3e0ec707e7da19aee9a29&chksm=806e3d34b719b422fedf9feffa136ddef2d638b59c80921764d60d22b283bc86aae93bfc1c7d&scene=27