What is a context manager

For resource management operations such as file operation and database connection, we must release after use, otherwise it is easy to cause resource leakage. To solve this problem, Python’s solution is the context manager. Context managers can help you automatically allocate and free resources, and the most typical application is the with statement. Let’s look at an example of opening a file.

for x in range(10000): 
    f = open('test.txt', 'w')
    f.write('hello world') 
Copy the code

This code means that we opened 10,000 files, but did not close them after using them. This is a typical example of resource leakage. This is an example of an error. We should write it this way.

for x in range(10000):
    with open('test.txt', 'w') as f:
        f.write('hello world')
Copy the code

Every time we open the file “test.txt” and write “Hello World”, the file will be automatically closed and the corresponding resources will be released to prevent resource leakage. The code for the with statement can also be replaced with the following form.

f = open('test.txt', 'w')
try:
    f.write('hello world')
finally:
    f.close()
Copy the code

Note that the finally statement is especially important to ensure that the file is eventually closed even if an error exception occurs while writing to the file. However, this code is redundant and easy to miss when compared to the with statement, so we generally prefer to use the with statement.

Implementation of the context manager

Let’s take a closer look at its internals and implementation. Here we define an upper and lower manager class, FileManager, that emulates Python’s operation of opening and closing files.

class FileManager: def __init__(self, name, mode): print('calling __init__ method') self.name = name self.mode = mode self.file = None def __enter__(self): print('calling __enter__ method') self.file = open(self.name, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): print('calling __exit__ method') if self.file: self.file.close() with FileManager('test.txt', 'w') as f: F. rite('hello world') print('write success') #### output #### calling __init__ method calling __enter__ method write success calling __exit__ methodCopy the code

This is the implementation of a class-based context manager. When we use a class to create a context manager, we need to include the “Enter” and “exit” methods. The Enter method returns the resources to be managed, and the exit method usually releases or clears resources. When we execute this context manager with the with statement, we do the following in turn.

  1. First the method “init()” is called, and the program initializes the object FileManager so that the name is “test.txt” and the mode is “w”;
  2. The method “enter()” is called, the file “test.txt” is opened in write mode, and the FileManager object assigned to the variable f is returned;
  3. The string “Hello world” is written to the file “test.txt”;
  4. The method “exit()” is called to close the previously opened stream.

It is worth mentioning that the parameters “exc_type, exc_val, exc_tb” in the method “exit()” represent exception_type, exception_value, and traceback, respectively. When we execute the with statement with the context manager, if an exception is thrown, the information about the exception is contained in these three variables, passed in the “exit()” method. Therefore, if you need to handle possible exceptions, you can add the appropriate exception handling code to “exit()”.

The context manager in Python can be implemented based on generators as well as classes. Let’s look at the following example. . You can use a decorator contextlib contextmanager to define themselves based on the context of the generator needed for the manager, to support with statement. Using the previous class context manager, FileManager, we can also use the following form:

from contextlib import contextmanager @contextmanager def file_manager(name, mode): try: f = open(name, mode) yield f finally: f.close() with file_manager('test.txt', 'w') as f: f.write('hello world')Copy the code

In this code, the function file_manager() is a generator, and when we execute the with statement, we open the file and return the file object f; When the with statement is finished, the file closing operation in the finally block is executed.

At this point, we have covered the implementation of both context managers. The two are functionally identical, but the class-based context manager is more flexible and suitable for large-scale system development. The context manager based on generator is more convenient and concise, suitable for small and medium-sized programs.

Welcome to leave a message and communicate with me. More interesting content, please pay attention to the public account Lao Han essay.