When we execute the statement block, we need some preparation actions, and after the execution is complete, we need to perform some finishing actions. For example: the file needs to be closed after reading and writing, the connection needs to be closed after the database is read and written, and the resources are locked and unlocked. In this case, Python provides the concept of context management, which can be used to process the preparation actions before the execution of the code block and the finishing actions after the execution through the context manager.
First look at the situation where you can't use the context manager
f =open("log.txt","w")try:
f.write("hello")finally:
f.close()
Use context manager
withopen("log.txt","w")as f:
f.write("hello")
When the statement ends, Python will automatically call the f.close() method for us
Theentermethod of the object returned by theopen("log.txt", "w") statement after with will be called, and the return value of __enter__ will be assigned to the variable after as
When with is executed, the __exit__ method of the front-end return object will be called.
Let's write a class to test:
classContextTest:
def __enter__(self):print("Enter enter!")return"Foo"
def __exit__(self,*args,**kwargs):print("Enter exit!")
def get_sample():returnContextTest()withget_sample()as sample:print(f"Sample: {sample}")
operation result:
Enter enter!
Sample: Foo
Enter exit!
According to the principle of the with statement above, we use the class to implement a class that supports the with statement to open files
classFile:
def __init__(self, file_name: str, method: str):
self.file_obj =open(file_name, method)
def __enter__(self):return self.file_obj
def __exit__(self, exc_type, exc_val, exc_tb):
self.file_obj.close()print(f"type: {exc_type}")print(f"value: {exc_val}")print(f"traceback: {exc_tb}")withFile('demo.txt',"w")as f:
f.useless_func()
We also implemented an exception handling here. Regarding exception handling, the with statement will be executed like this
exc_type, exc_val, exc_tb to the __exit__ method__exit__ method to handle exceptions__exit__ returns True, then the exception is ignored.__exit__ returns anything other than True, then this exception will be thrown by the with statement.The output result is:
type:<class'AttributeError'>
value:'_io.TextIOWrapper' object has no attribute 'useless_func'
traceback:<traceback object at 0x000001D259D82908>Traceback(most recent call last):...
AttributeError:'_io.TextIOWrapper' object has no attribute 'useless_func'
from contextlib import contextmanager
@ contextmanager
def my_open(filename, mode):
file_obj =open(filename, mode)try:yield file_obj.readlines()
except Exception as e:
raise e
finally:
file_obj.close()if __name__ =='__main__':withmy_open(r'demo.txt','r')as f:for line in f:print(line)
The code before yield is executed by the __enter__ method, and the code after yield is executed by the __exit__ method. Essentially, it is the __enter__ and __exit__ methods. Because the decorator of @contextmanager accepts a generator, use the yield statement to output the variables of with ... as var, and then the with statement can work normally
In addition to taking over the opening and closing of files, databases, etc., we can also use the features of @contextmanager to do some great things. If we want to automatically execute specific codes before and after a certain piece of code is executed, we can also use @contextmanager to achieve
@ contextmanager
def tag(name):print("<%s>"% name)yieldprint("</%s>"% name)withtag("h1"):print("hello")print("world")
# Output
< h1>
hello
world
< /h1>
If an object does not implement a context, we cannot use it in the with statement. At this time, we can use closing to turn the object into a context object. For example, use urlopen() with with statement
from contextlib import closing
from urllib.request import urlopen
withclosing(urlopen('https://www.python.org'))as page:for line in page:print(line)
Let's look at the source code of this magical closing
classclosing(AbstractContextManager):"""Context to automatically close something at the end of a block.
Code like this:withclosing(<module>.open(<arguments>))as f:<block>
is equivalent to this:
f =<module>.open(<arguments>)try:<block>finally:
f.close()"""
def __init__(self, thing):
self.thing = thing
def __enter__(self):return self.thing
def __exit__(self,*exc_info):
self.thing.close()
It's the same as what we did with the class method above~
Liao Xuefeng's Python tutorial-contextlibTwo implementation methods of python with statement context managementUse and principle of with in Python
Recommended Posts