① The with statement is a compact version of the try/finally statement

In our daily use scenario, often operating some resources, such as the file object, database connection and a Socket connection, resources after the operation, regardless of the success of operation, the most important thing is to close the resources, resources open too much and not closed, complains, file operations, for example, usually we will write like this:

f = open('file.txt', 'w')
try:
    f.write("Hello")
finally:
    f.close()Copy the code

But since the close method is required, there is no need to call it explicitly, so Python gives us a more elegant way to use the with statement:

with open('file.txt', 'w') as f:
    f.write("Hello")Copy the code

After exiting the code block under the with statement, the f object will automatically execute its own close method to achieve a concise and elegant resource release.

② Context manager principle

The f object automatically executes its own close method because it is a context manager, so let’s talk about what a context manager is.

Context managers are objects that internally implement __enter__ and __exit__ methods (such as the object obtained by the EXPR expression below)

It is commonly used as follows:

with EXPR as VAR:
    BLOCKCopy the code

The execution of the above code is equivalent to:

ContextManager = EXPR
VAR = ContextManager.__enter__()
try:
    BLOCK
finally:
    ContextManager.__exit__()Copy the code

An f object defines its own close method inside its __exit__ method, which automatically closes itself when a BLOCK is finished executing.

③ Custom context manager

To verify this, we define a file class that internally implements __enter__ and __exit__ methods:

class File: def __init__(self, filename, mode): self.filename = filename self.mode = mode def __enter__(self): Self. f def __exit__(self, exc_type=None, exc_val=None, exc_val=None, Exc_tbs =None): print(" exit ") self.f.close()Copy the code

In this case, the File class is a context manager

We use the File class to write to the File using the with statement and the try/finally statement, respectively

Execute with the with statement:

With File('file.txt', 'w') as f: print( ) f.write('Hello')Copy the code

Console output:

Enter writing... exitCopy the code

And you get a file called file.txt with Hello

Execute with a try/finally statement:

ContextManager = File('file.txt', 'w') VAR = contextManager.__enter__ () try: print(" writing..." ) VAR.write('Hello') finally: ContextManager.__exit__()Copy the code

Console output:

Enter writing... exitCopy the code

And you get a file called file.txt with Hello

The output of the two is consistent, so the equivalence relation of the execution process in ② is verified to be correct

④ __enter__ and __exit__ methods description

1. __enter__ method description

The context manager’s __enter__ method can return a value. By default, it returns None. as… With EXPR as VAR assigns the return value of the EXPR object’s __enter__ method to VAR.

Of course with… as… Use alone with… The context manager’s __enter__ method still works, except that the return value is not assigned to a variable, and the code block below with cannot use the return value.


2. __exit__ method description

The context manager’s __exit__ method accepts three arguments exc_type, exc_val, and exc_tb, which are type(e), STR (e), and e.__traceback__ if the code BLOCK exits with an exception E, or None otherwise.

The __exit__ method can also return a value, which should be a Boolean True or False, default to None (False). If False, the exception is thrown and the user needs to handle the exception. If True, the exception is ignored.

Contextmanager decorator

Python also provides a contextmanager decorator that allows the user to define a generator as a contextmanager. The decorator splits the code in the generator into two parts using the yield statement, preceded by the __enter__ method, The code after yield is the __exit__ method. The return value of yield is the return value of the __enter__ method, which is assigned to the variable after AS.

Here we also implement a contextmanager for a file using the contextmanager decorator:

from contextlib import contextmanager @contextmanager def open_file(filename, mode): Print (' enter ') f = open(filename, mode) try: yield f finally: print(' exit ') f.close()Copy the code

Use try/except/finally to ensure that the file will be closed properly even if an exception occurs during the yield process.

Execute with the with statement:

With open_file (' file. TXT ', 'w') as f: print (" is written to..." ) f.write('Hello')Copy the code

The execution results match the previous contextmanager execution results, indicating that the contextmanager decorator can also define a contextmanager.

The contextmanager is an object that implements the __enter__ and __exit__ methods internally, so if you are interested in the contextmanager decorator, you can look at the source of the contextmanager decorator and see how it turns a generator into a contextmanager. The contextManager decorator is the contextManager decorator that processes the generator into an object that internally implements __enter__ and __exit__ methods.

6. Summary

1. The with statement is an alternative to the try/finally statement, simplifying cleanup after resource calls

2. The with statement operates on the context manager, which internally implements the __enter__ and __exit__ methods

3. The __enter__ method can return a value, which is passed with… as… As in the statement is assigned to the variable following it; __exit__ returns a Boolean value. If False, the exception is thrown and the user needs to handle the exception. If True, the exception is ignored

4. Python also provides the contextmanager decorator, which further simplifies the definition of the contextmanager by processing the generator into an object that internally implements the __enter__ and __exit__ methods