Python 高手编程系列九:上下文管理器 — with 语句

为了确保即使在出现错误的情况下也能运行某些清理代码,try...finally 语句是

很有用的。这一语句有许多使用场景,例如:

• 关闭一个文件。

• 释放一个锁。

• 创建一个临时的代码补丁。

• 在特殊环境中运行受保护的代码。

with 语句为这些使用场景下的代码块包装提供了一种简单方法。即使该代码块引发了异常,你也可以在其执行前后调用一些代码。例如,处理文件通常采用这种方式:

hosts = open('/etc/hosts')

try:

... for line in hosts:

... if line.startswith('#'):

... continue

... print(line.strip())

... finally:

... hosts.close()

...

127.0.0.1 localhost

255.255.255.255 broadcasthost

::1 localhost

利用 with 语句,上述代码可以重写为:

with open('/etc/hosts') as hosts:

... for line in hosts:

... if line.startswith('#'):

... continue

... print(line.strip())

...

127.0.0.1 localhost

255.255.255.255 broadcasthost

::1 localhost

在前面的示例中,open 的作用是上下文管理器,确保即使出现异常也要在执行完 for

循环之后关闭文件。

与这条语句兼容的其他项目是来自 threading 模块的类:

• threading.Lock

• threading.RLock

• threading.Condition

• threading.Semaphore

• threading.BoundedSemaphore

一般语法和可能的实现

with 语句的一般语法的最简单形式如下:

with context_manager:

代码块

...

此外,如果上下文管理器提供了上下文变量,可以用 as 子句保存为局部变量:

with context_manager as context:

代码块

...

注意,多个上下文管理器可以同时使用,如下所示:

with A() as a, B() as b:

...

这种写法等价于嵌套使用,如下所示:

with A() as a:

with B() as b:

...

作为一个类

任何实现了上下文管理器协议(context manager protocol)的对象都可以用作上下文管

理器。该协议包含两个特殊方法。

enter (self):更多内容请访问https://docs.python.org/3.3/reference/datamodel.html

#object.enter

exit (self, exc_type, exc_value, traceback):更多内容请访问

https://docs.python.org/3.3/reference/datamodel.html#object.**exit** 。

简而言之,执行 with 语句的过程如下:

• 调用__enter__方法。任何返回值都会绑定到指定的 as 子句。

• 执行内部代码块。

• 调用__exit__方法。

__exit__接受代码块中出现错误时填入的 3 个参数。如果没有出现错误,那么这 3 个

参数都被设为 None。出现错误时,__exit__不应该重新引发这个错误,因为这是调用者

(caller)的责任。但它可以通过返回 True 来避免引发异常。这可用于实现一些特殊的使用

场景,例如下一节将会看到的 contextmanager 装饰器。但在大多数使用场景中,这一

方法的正确行为是执行类似于 finally 子句的一些清理工作,无论代码块中发生了什么,

它都不会返回任何内容。

下面是某个实现了这一协议的上下文管理器示例,以更好地说明其工作原理:

class ContextIllustration:

def enter (self):

print('entering context')

def exit (self, exc_type, exc_value, traceback):

print('leaving context')

if exc_type is None:

print('with no error')

else:

print('with an error (%s)' % exc_value)

没有引发异常时的运行结果如下:

with ContextIllustration():

... print("inside")

...

entering context

inside

leaving context

with no error

引发异常时的输出如下:

with ContextIllustration():

... raise RuntimeError("raised within 'with'")

...

entering context

leaving context

with an error (raised within 'with')

Traceback (most recent call last):

File "", line 2, in

RuntimeError: raised within 'with'

相关推荐
Database_Cool_1 小时前
阿里云 RDS MySQL 降本增效实战:从规格选型到成本优化,月成本降低64%全攻略
mysql·阿里云·云计算
java_logo1 小时前
Apache Doris Docker 部署指南:实时分析数据库实战
数据库·docker·apache·doris·apache doris·轩辕镜像·docker部署doris
广州灵眸科技有限公司9 小时前
xfce桌面触摸校准:基于灵眸科技EASY-EAl-Orin-Nano
数据库·windows·科技
大模型码小白10 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
麻雀飞吧10 小时前
最新量化学习路径,交易认知和技术实现要并行
人工智能·python
Cloud云卷云舒11 小时前
云卷云舒:从Oracle/MySQL迁移到HaishanDB:迁移评估工具核心技术拆解
mysql·oracle·ai-native·haishandb·信创数据库替换
憧憬成为web高手12 小时前
皮卡丘靶场速通--sql 2
数据库·sql·mybatis
段一凡-华北理工大学12 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
oradh14 小时前
Oracle XTTS实现跨版本迁移和升级(Oracle 11g单库升级至19C RAC集群)
数据库·oracle·11g升级19c·xtts跨版本迁移和升级
C^h14 小时前
python函数学习
人工智能·python·机器学习