Python上下文管理器(Context managers)

Python上下文管理器(Context managers)

 

上下文管理器(context manager https://docs.python.org/zh-cn/3/glossary.html#term-context-manager

在 with 语句中使用,通过定义 __enter__() 和 __exit__() 方法来控制环境状态的对象。

【with 语句上下文管理器https://docs.python.org/zh-cn/3/reference/datamodel.html#context-managers

with 语句 https://docs.python.org/zh-cn/3/reference/compound_stmts.html#with

 

上下文管理器允许你在有需要的时候,精确地分配和释放资源。上下文管理器是指在一段代码执行之前执行一段代码,用于一些预处理工作;执行之后再执行一段代码,用于一些清理工作。比如打开文件进行读写,读写完之后需要将文件关闭。在上下文管理协议中,有两个方法__enter__和__exit__,分别实现上述两个功能。比如在数据库操作中,操作之前需要连接数据库,操作之后需要关闭数据库。

讲到上下文管理器最广泛的案例就是with语句了。with语法。基本语法格式为:

with EXPR [as VAR]:

BLOCK

其中的EXPR是上下文表达式(Context Expression),该表达式要返回一个上下文管理器对象。返回的是一个对象,var用来保存EXPR表达式返回的对象,可以有单个或者多个返回值。这里的as VAR可以省略,如果指定了 as 子句的话,会将上下文管理器的 __enter__() 方法的返回值赋值给VAR。VAR可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)。

代码块BLOCK, with 语句包裹起来的代码块,在执行语句体之前会调用上下文管理器的 __enter__() 方法,执行完语句体之后会执行 __exit__() 方法。在这里VAR可以当做普通变量使用。

 

 

以打开一个文件hello.txt并写入 hello, world 为例

我们先对比如下两种方式:

方式一,代码如下:

f = open("d:/hello.txt", 'w')

try:

         f.write('hello, world')

finally:

         f.close()

 

方式二,代码如下:

with语句通过在上下文管理器中封装try…finally语句的标准用法来简化异常处理

with open('d:/hello.txt', 'w') as f:

         f.write('hello, world')

 

Python 对一些内建对象进行改进,加入了对上下文管理器的支持,可以用于 with 语句中,比如可以自动关闭文件、线程锁的自动获取和释放等。方式二可以验证,内置函数 open ()就具有对上下文管理器的支持。

 

如何来实现我们自己的上下文管理器

下面介绍如何来实现我们自己的上下文管理器?或者说,如何使自定义的对象支持with?

自定义对象实现上下文管理器即可。有两种方式:基于类实现方式和基于生成器实现方式。

上下文管理器是一个简单的协议(接口),自定义的对象需要遵循这个协议(接口)来支持with语句。具体做法,向自定义对象中添加__enter__和__exit__方法,Python将在资源管理的适当时间调用这两种方法。

还是用前面提到的 打开一个文件hello.txt并写入 hello, world 例子,

☆基于类实现方式

#先定义类
class ManagedFile:
	def __init__(self, name):
		self.name = name
	def __enter__(self):
		self.file = open(self.name, 'w')
		return self.file
	def __exit__(self, exc_type, exc_val, exc_tb):
		if self.file:
			self.file.close()

#提示ManagedFile类遵循上下文管理器协议,与原open()一样也支持with语句

with ManagedFile('d:/hello.txt') as f:
	f.write('hello, world')

进入with语句上下文,Python调用__enter__获取资源,离开with语句上下文,Python调用__exit__释放资源。

 

☆基于生成器实现

利用标准库contextlib模块的contextmanager装饰器重写之前的ManagedFile上下文管理器

from contextlib import contextmanager
@contextmanager
def managed_file(name):
	try:
		f = open(name, 'w')
		yield f
	finally:
		f.close()

#提示managed_file遵循上下文管理器协议

with managed_file('d:/hello.txt') as f:
	f.write('hello, world')

 

 

 

python3,浅谈with的神奇魔法 https://blog.csdn.net/lxy210781/article/details/81176687

深入理解 Python 中的上下文管理器 https://juejin.cn/post/6844903795403522056

python之上下文管理器——with语句详解https://blog.csdn.net/weixin_45950544/article/details/103940387

python上下文管理器ContextLib及with语句https://blog.csdn.net/pipisorry/article/details/50444736

 

上一篇:LeetCode 181. Employees Earning More Than Their Managers (sql)


下一篇:leetcode Employees Earning More Than Their Managers题解