Home  >  Article  >  Backend Development  >  Python Programming: Easily Understand Context Manager (Context Manager)

Python Programming: Easily Understand Context Manager (Context Manager)

PHPz
PHPzforward
2023-04-12 14:07:132261browse

Preface

This article focuses on the explanation and application of Python context management. Or through code examples, comparative understanding and learning, in order to achieve the understanding, mastery and application of "more speed, better economy". Without further ado, let’s start——

1. What is a context manager

A context manager is an object that defines the context manager to be created when executing a with statement. Runtime context. A context manager is a runtime that automatically handles entry and exit for the context in which a block of code executes. Context managers are typically called using a with statement, but can also be used by calling their methods directly.

Typical uses of context managers include saving and restoring various global states, locking and unlocking resources, closing open files, etc.

In this chapter, we will learn how to use context managers in Python and how to customize context managers.

1.With statement

The with statement is used for the execution of the method wrapping block defined by the context manager. This allows to encapsulate the common try...except...finally usage pattern for easy reuse. The with statement provides shorter and reusable code compared to the traditional try...except...finally block.

In the Python standard library, many classes support the with statement. A very common example is the built-in open() function, which provides a pattern for processing file objects using the with statement.

The following is the general syntax of the with statement:

with expression as target:
# 使用target
# 来处理事情

Let’s look at an example of using the open() function. There is a text file in the files folder of the current project. The file name is color_names.txt, which contains some color names (you can provide some text content yourself). We want to open and print the contents of this file by using the open() function and the with statement. The code example is as follows:

import os
fileDirPath = os.getcwd()+os.sep+"ctxManager"+os.sep #自定义文件路径
# 指定文件路径和名称
path = fileDirPath+'files/color_names.txt'

# with 语句
with open(path, mode='r') as file:
# 读取文件内容
print(file.read())

The output result of running the program is as follows

red
orange
yellow
green
blue
white
black

In the above list, what you see is a common use case of the with statement. We use the open() function to open the file on the given path (path), and the open() function returns the file object in read-only mode. The code then uses this file object to read and print out its contents through the code: print(file.read()).

The above example is a typical usage of the context manager. In order to better understand and apply context managers, we have to continue reading.

3. Context Manager Protocol

The Context Manager Protocol (Context Manager Protocol), to put it bluntly, is the processing mechanism of the context manager, or the predetermined protocol standard. This part can also be found here: Python Core Protocol. For the sake of independence in reading, let’s talk about it again here.

Python’s with statement supports the concept of runtime context defined by a context manager. This is accomplished through a pair of methods that allow a user-defined class to define a runtime context that is entered before the statement body is executed and exited at the end of the statement.

The methods mentioned earlier are called context manager protocols. Let’s look at these two methods in detail:

1) __enter__(self)

This method is called by the with statement to enter the runtime context related to the current object . The with statement binds the return value of this method to the target (if any) specified in the statement's as clause.

The context manager returned in the above example is the file object. Behind the scenes, the file object returns itself from __enter__() to allow open() to be used as a contextual expression in a with statement.

2)__exit__(self, exc_type, exc_value, traceback):

This method is called when execution leaves the with code block. It exits the runtime context associated with this object. The parameters describe the exception information that caused the context to exit. If the context is exited without an exception, all three parameters will be None.

If an exception is provided and you want the method to suppress the exception (i.e., prevent it from being propagated), then it should return a True value. Otherwise, the exception will be handled normally when exiting this method. The __exit__() method returns a Boolean value, which can be True or False.

The process of executing a with statement using methods in the context manager protocol is as follows:

with EXPRESSION as TARGET:
SUITE
  • Calculate the context expression (EXPRESSION) to obtain the context manager.
  • Load the context manager's __enter__() for subsequent use.
  • Load the context manager's __exit__() for subsequent use.
  • Call the __enter__() method of the context manager.
  • If a TARGET is included in the with statement, the return value of __enter__() will be assigned to it.
  • Execution suite (code block in the scope of the with statement).
  • Call the __exit__() method of the context manager. If the exception caused the suite to exit, its type, value, and traceback are passed as arguments to __exit__(). Otherwise, three None parameters will be provided.

If the suite exits for any reason other than an exception, the return value of __exit__() is ignored and execution of subsequent code (if any) continues at the normal location for the exit type being performed.

4. Class form context manager

Now that we understand the basic idea behind the context manager protocol, let’s implement it in a class. This class will be our context manager and we will use it later in the with statement.

定义的上下文管理器类参考示例清单如下:

# 自定义上下文管理器类
class CustomContextManager:
# 初始化方法init -> 定义一些变量
def __init__(self, path, mode):
self.path = path
self.mode = mode
self.file = None

# __enter__ method -> open the file
def __enter__(self):
self.file = open(self.path, self.mode)
return self.file

# exit method to close the file

def __exit__(self, exc_type, exc_value,exc_traceback):
self.file.close()

我们的CustomContextManager类实现了成为上下文管理器的必要方法:__enter__和__exit__。

在__init__方法中,它定义了三个实例变量来存储路径、模式和文件对象。

在__enter__方法中,它使用内置的open()函数打开指定路径中的文件。由于open()函数返回file对象,我们将其赋值给self.file属性。

在__exit__方法中,我们将文件关闭:self.file.close()。

__exit__方法接受三个参数,它们是上下文管理器协议所需要的。

现在我们可以在with语句中使用自定义上下文管理器。

使用自定义的类上下文管理器的示例(和我们前面的示例雷同):

# 应用示例
import os
fileDirPath = os.getcwd()+os.sep+"ctxManager"+os.sep
# 在with语句中使用自定义上下文管理器
file_path = fileDirPath + 'files/color_names.txt'

with CustomContextManager(path=file_path, mode='r') as file:
#输出文件file内容
print(file.read())

运行输出结果这里不再赘述。简单解释一下代码。

上面清单中,在with语句中使用CustomContexManager类,通过它来读取文件内容并打印出来。下面是这个自定义上下文管理器幕后的故事:

1)在with行,调用类CustomContextManager的方_enter__法

2) __enter__方法打开文件并返回它。

3)我们将打开的文件简单地命名为file。

4)在with语句块中,读取文件内容并将其打印出来。

5)with语句自动调用__exit__方法。

6)__exit__方法关闭文件。

我们再来定义另一个上下文管理器类。这次我们想打印指定文件夹中的文件列表。

参考实现的代码清单如下:

class ContentList:
'''Prints the content of a directory'''

def __init__(self, directory):
self.directory = directory

def __enter__(self):
return os.listdir(self.directory)

def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
print("Error getting directory list.")
return True

# 输出项目目录下的内容
project_directory = '.'
with ContentList(project_directory) as directory_list:
print(directory_list)

在代码清单中,我们定义了一个新的上下文管理器。这个类的名字是ContentList。为什么它是一个上下文管理器?因为它实现了上下文管理器协议(__enter__和__exit__方法)。

我们将目录路径作为类构造函数__init__方法中的参数。

在__enter__方法中,只需调用os模块中的listdir()方法,就可以获得该目录中的内容列表:os.listdir(self.directory)。然后返回这个列表。请注意,在这个上下文管理器中我们的__enter__方法返回一个列表。

在__exit__方法中,我们检查是否存在任何错误。如果我们的上下文管理器中有错误,exc_type、exc_val、exc_tb参数值将不会为None。因此,我们检查exc_type是否为None以打印错误文本。

在with语句中使用该上下文管理器。由于它返回一个列表对象,我们只需将返回值赋值给directory_list变量。在with语句的主体中,我们打印这个列表。运行程序后在输出中,可以看到项目目录中的内容列表。记住,"."表示当前目录,在我们的例子中是项目根目录(由于项目环境不同,输出内容可能也不一样)。

6. 函数形式上下文管理器

前文中,我们学习了如何使用类语法定义上下文管理器。但是有点繁琐和冗长。因为需要明确地实现__enter__和exit__方法,还需要处理可能的异常。所以希望Python中能有在创建上下文管理器更好的方法:基于函数的上下文管理器。

其实函数上下文管理器是使用生成器和contextlib.contextmanager装饰器的特殊函数。 contextlib.contextmanager装饰器负责实现上下文管理器协议。

下面就来定义一个函数型上下文管理器。

from contextlib import contextmanager

# 定义上下文管理器函数
@contextmanager
def function_based_context_manager():
print("进入上下文: __enter__")
yield "这是个基于上下文管理器的函数"
print("离开上下文: __exit__")

# with语句中使用上下文管理器函数
with function_based_context_manager() as yield_text:
print(yield_text)

运行程序输出结果类似如下:

进入上下文: __enter__
这是个基于上下文管理器的函数
离开上下文: __exit__

在上面代码中,我们定义了一个作为上下文管理器的自定义函数。contextmanager装饰器将常规函数转换为全堆栈上下文管理器(自动实现上下文管理器的协议)。如果你为函数提供了@contextmanager装饰器,就不需要担心实现__enter__和__exit__函数。

代码中的yield语句在基于类的上下文管理器中的__enter__方法中充当返回语句。由于我们使用了yield语句,故此,这个基于函数的上下文管理器也是生成器函数。

再来定义一个新的上下文管理器。这一次,它将以写的模式打开一个文件并添加一些文本。示例如下:

Python Programming: Easily Understand Context Manager (Context Manager)

代码清单

在清单中,我们定义了一个基于函数的上下文管理器。在try块中,它尝试打开指定路径中的文件,并指定了文件的默认编码集。如果它成功地打开它,那么它将生成(返回)file_object。在finally块中,我们检查是否有一个file_object要关闭。如果file_object不是None,则关闭file_object。

In the with statement, we call the context manager with the file name funBasedContextManagers.txt. The context manager opens the file in write mode and returns the file object, which we simply name file. Then write some text into this file. Remember, 'w' mode will create an empty file if such a file does not exist.

Run the above program. If the file does not exist, a file with the corresponding name will be generated and the written content will be retained. If the file exists, the content is written to the source file each time. Please pay attention to this operation.

To handle "finishing" work like this, it is particularly convenient to use a context manager, especially when it comes to database operations. For example, you can wrap one yourself to automatically close the connection, etc.

Summary of this article

In this issue we introduced the relevant programming content of context managers, such as how to create context managers, context manager protocols, custom class-form context managers and functional Context managers etc. Most of the relevant content is demonstrated and explained with practical code. If you want to improve your programming skills, typing code with your hands is an essential requirement.

The above is the detailed content of Python Programming: Easily Understand Context Manager (Context Manager). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:51cto.com. If there is any infringement, please contact admin@php.cn delete