The principle of context in python

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

Guess you like

Origin blog.csdn.net/qq_43745578/article/details/129431509