Python 上下文管理器和 with 语句
1. 上下文管理器概念
什么是 Python
的上下文管理器(Context Managers
)呢?
含有 __enter__
和 __exit__
方法的对象就是。上下文管理器存在的目的是管理 with
语句,就像是迭代器的存在是为了管理 for
语句一样。
with 上下文管理器:语句体
2. with 语句
当 with
遇到上下文管理器,就会在执行语句体之前,先执行上下文管理器的 __enter__
方法,然后再执行语句体,执行完语句体后,最后执行 __exit__
方法。举个例子:
class Foo(object):def __init__(self):print('把大象放冰箱总共分几步?')def __enter__(self):print('把冰箱门打开')def __exit__(self, exc_type, exc_val, exc_tb):print('把冰箱门关上')obj = Foo()with obj:print('把大象放进去')
输出:
把大象放冰箱总共分几步?
把冰箱门打开
把大象放进去
把冰箱门关上
with
有一个很重要的作用是简化 try/finally
模式,无论何种异常发生,finally
字句都会执行。
通常 finally
子句中的代码用于释放重要的资源,或者还原临时变更的状态。比如,不管大象能不能装进冰箱,最终 finally
你都得把冰箱门关上,用代码解释就是:
class Foo(object):def __init__(self):print('把大象放冰箱总共分几步?')def __enter__(self):print('把冰箱门打开')def __exit__(self, exc_type, exc_val, exc_tb):print('把冰箱门关上')obj = Foo()with obj:raise ImportError # 这里发生严重的错误,这段程序崩溃了print('把大象放进去')
输出结果:
把大象放冰箱总共分几步?
把冰箱门打开
把冰箱门关上
Traceback (most recent call last):File "char_1.py", line 15, in <module>raise ImportError
ImportError
有了 with
保驾护航,装大象的程序崩溃了,也能把冰箱门关上。
3. 上下文管理器写法
Python
提供了更简便的上下文管理器写法,使用 @contextmanager
。在使用 @contextmanager
装饰的生成器中,yield
语句的作用是把所在函数分成两部分:
yield
语句前面的代码在with
块开始时执行;yield
语句后面的代码在with
块结束时执行;
那么上面的例子就可以简写成为:
from contextlib import contextmanager@contextmanager
def fridge_operation():print('把大象放冰箱总共分几步?')print('把冰箱门打开')yieldprint('把冰箱门关上')def put_elephant_in_fridge():print('把大象放进去')with fridge_operation() :put_elephant_in_fridge()
输出:
把大象放冰箱总共分几步?
把冰箱门打开
把大象放进去
把冰箱门关上
但需要特别注意的是,如果使用 @contextmanager
来实现上下文管理器,要把 yield
语句放在 try/finally
语句中(或者放在 with
语句中),个人觉得 Python 在这一点上把 @contextmanager
变的十分具有迷惑性,它可以把生成器函数变成上下文管理器,但是它不能联手与 with
默认完成 finally
功能,用代码说明:
from contextlib import contextmanager@contextmanager
def fridge_operation():print('把大象放冰箱总共分几步?')print('把冰箱门打开')yieldprint('把冰箱门关上')def put_elephant_in_fridge():print('把大象放进去')with fridge_operation() :raise ImportError # 这里发生严重的错误,这段程序崩溃了put_elephant_in_fridge()
输出:
把大象放冰箱总共分几步?
把冰箱门打开
Traceback (most recent call last):File "char_1.py", line 15, in <module>raise ImportError
ImportError
发现了么?冰箱门没关上。冰箱门没关上,我要你上下文管理器有什么用?所以我们需要把 yield
语句放在 try/finally
语句中,如下:
from contextlib import contextmanager@contextmanager
def fridge_operation():print('把大象放冰箱总共分几步?')print('把冰箱门打开')try:yieldfinally:print('把冰箱门关上')with fridge_operation():raise ImportErrorprint('把大象放进去')
输出:
把大象放冰箱总共分几步?
把冰箱门打开
把冰箱门关上
Traceback (most recent call last):File "char_1.py", line 13, in <module>raise ImportError
ImportError
至此,@contextmanager
巧妙的将三个不同的 Python
特性结合到了一起:函数装饰器,生成器和 with
语句。
参考:
https://book.pythontips.com/en/latest/context_managers.html
Python 上下文管理器和 with 语句相关推荐
- Python 上下文管理器与with语句
Python中把进入代码块前调用__enter__ 方法并在离开代码块后调用__exit__方法的对象作为上下文管理器,本文中我们就来深入解析Python中的上下文管理器,来看看上下文管理器的作用及用 ...
- 此上下文中不支持函数定义。请在代码文件中创建函数。_深入解析Python上下文管理器,让你不再迷茫!...
1. 上下文管理器 一个类只要实现了 __enter__() 和 __exit__() 这个两个方法,通过该类创建的对象我们就称之为上下文管理器. 上下文管理器可以使用 with 语句,with语句之 ...
- Python 上下文管理器和with块 二
标准库中还有个contextlib 模块,提供一些实用工具, closing 如果对象提供了 close() 方法,但没有实现 __enter__/__exit__ 协议,那么可以使用这个函数构建上下 ...
- Python 上下文管理器和with块 一
上下文管理器对象存在的目的是管理 with 语句,就像迭代器的存在是为了管理 for 语句一样 上下文管理器协议包含 __enter__ 和 __exit__ 两个方法 把值绑定到目标变量上(as 子 ...
- Python上下文管理器的魔力
点击关注我哦 一篇文章带你了解Python上下文管理器的魔力 小编将为您准备一份很棒的Python上下文管理器使用指南,这将使您的代码更具可读性和可靠性,降低您的错误发生率. 资源管理器是我们在任何编 ...
- 爱上python系列------python上下文管理器(二):对suppress进行装饰器重新实现
python上下文管理器可以做的事情简直不能太多 这不,官方的文档实现了一个方法suppress,用于处理异常 from contextlib import suppresswith suppress ...
- python语言使用什么语句实现上下文管理协议_Python 技巧探究:上下文管理器和with语句...
一:前言 Python 里面的 with 语句是被认为是晦涩难懂的特征之一,但是当你窥视它的内部你就会发现这里面并没有什么魔法.事实上它可以帮助我们写一些整洁和可读性高的代码. 那么 with 语句适 ...
- Python进阶(上下文管理器与with语句)
/*上下文管理器必须有__enter__和__exit__方法*/ class MyResource:def __enter__(self):print('链接资源')return self/*__e ...
- 神经网络与深度学习——TensorFlow2.0实战(笔记)(四)(python上下文管理器)
with语句 使用with语句替代try-finally 语句,代码更加的简洁清晰 对于需要对资源进行访问的任务,无论在代码运行过程中,是否发 生异常,都会执行必要的清理操作,释放资源. 1. wit ...
最新文章
- ArrayList和LinkedList的add(E)性能秘密
- python123数字形式转换_【Python系统学习02】数据类型与类型转换
- 访问 IIS 元数据库失败解决问题的方法
- buuctf 你居然赶我走1
- oracle查看语句执行历史,AWT查看oracle历史sql语句执行
- python哪个版本支持xp_windows支持哪个版本的python
- java 流式_Java开发笔记(七十二)Java8新增的流式处理
- UI设计干货模板|首页设计技巧
- oracle 值安全性,Oracle Solaris 11 安全性預設值
- linux ubuntu/centos git 客户端编译安装升级
- Spring Boot(十八):使用Spring Boot集成FastDFS
- 人工智能聊天机器人(有详细安装教程)/ 自动学习型
- 10-Ubuntu-ftp客户端
- OpenMP学习笔记1
- python tushare量化股票大数据分析整合版
- leetcode 给N x 3网络图涂色的方案数
- Speedoffice(PPT)如何设置幻灯片大小
- Spring-04-Spring的入门配置
- Java工程师初学Android(四)(转)
- 服务器宠物系统,你们升级我抓宠,PVX也能从剑网三怀旧服的升级热潮中找到快乐!...
热门文章
- 2022-2028年中国帘子布行业市场研究及前瞻分析报告
- 2022-2028年中国高粘保护膜行业市场专项调研及发展趋势分析报告
- 2022-2028年中国高阻隔片材基膜行业市场供需形势及前瞻分析报告
- Linux shell 学习笔记(11)— 理解输入和输出(标准输入、输出、错误以及临时重定向和永久重定向)
- Tengine MLOps概述
- Recommenders with TensorRT
- 2021年大数据ELK(十六):Elasticsearch SQL(职位查询案例)
- Lumen报class does not exist的mailer坑
- CSS 选择器:BeautifulSoup4解析器
- CSS Modules