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 语句相关推荐

  1. Python 上下文管理器与with语句

    Python中把进入代码块前调用__enter__ 方法并在离开代码块后调用__exit__方法的对象作为上下文管理器,本文中我们就来深入解析Python中的上下文管理器,来看看上下文管理器的作用及用 ...

  2. 此上下文中不支持函数定义。请在代码文件中创建函数。_深入解析Python上下文管理器,让你不再迷茫!...

    1. 上下文管理器 一个类只要实现了 __enter__() 和 __exit__() 这个两个方法,通过该类创建的对象我们就称之为上下文管理器. 上下文管理器可以使用 with 语句,with语句之 ...

  3. Python 上下文管理器和with块 二

    标准库中还有个contextlib 模块,提供一些实用工具, closing 如果对象提供了 close() 方法,但没有实现 __enter__/__exit__ 协议,那么可以使用这个函数构建上下 ...

  4. Python 上下文管理器和with块 一

    上下文管理器对象存在的目的是管理 with 语句,就像迭代器的存在是为了管理 for 语句一样 上下文管理器协议包含 __enter__ 和 __exit__ 两个方法 把值绑定到目标变量上(as 子 ...

  5. Python上下文管理器的魔力

    点击关注我哦 一篇文章带你了解Python上下文管理器的魔力 小编将为您准备一份很棒的Python上下文管理器使用指南,这将使您的代码更具可读性和可靠性,降低您的错误发生率. 资源管理器是我们在任何编 ...

  6. 爱上python系列------python上下文管理器(二):对suppress进行装饰器重新实现

    python上下文管理器可以做的事情简直不能太多 这不,官方的文档实现了一个方法suppress,用于处理异常 from contextlib import suppresswith suppress ...

  7. python语言使用什么语句实现上下文管理协议_Python 技巧探究:上下文管理器和with语句...

    一:前言 Python 里面的 with 语句是被认为是晦涩难懂的特征之一,但是当你窥视它的内部你就会发现这里面并没有什么魔法.事实上它可以帮助我们写一些整洁和可读性高的代码. 那么 with 语句适 ...

  8. Python进阶(上下文管理器与with语句)

    /*上下文管理器必须有__enter__和__exit__方法*/ class MyResource:def __enter__(self):print('链接资源')return self/*__e ...

  9. 神经网络与深度学习——TensorFlow2.0实战(笔记)(四)(python上下文管理器)

    with语句 使用with语句替代try-finally 语句,代码更加的简洁清晰 对于需要对资源进行访问的任务,无论在代码运行过程中,是否发 生异常,都会执行必要的清理操作,释放资源. 1. wit ...

最新文章

  1. ArrayList和LinkedList的add(E)性能秘密
  2. python123数字形式转换_【Python系统学习02】数据类型与类型转换
  3. 访问 IIS 元数据库失败解决问题的方法
  4. buuctf 你居然赶我走1
  5. oracle查看语句执行历史,AWT查看oracle历史sql语句执行
  6. python哪个版本支持xp_windows支持哪个版本的python
  7. java 流式_Java开发笔记(七十二)Java8新增的流式处理
  8. UI设计干货模板|首页设计技巧
  9. oracle 值安全性,Oracle Solaris 11 安全性預設值
  10. linux ubuntu/centos git 客户端编译安装升级
  11. Spring Boot(十八):使用Spring Boot集成FastDFS
  12. 人工智能聊天机器人(有详细安装教程)/ 自动学习型
  13. 10-Ubuntu-ftp客户端
  14. OpenMP学习笔记1
  15. python tushare量化股票大数据分析整合版
  16. leetcode 给N x 3网络图涂色的方案数
  17. Speedoffice(PPT)如何设置幻灯片大小
  18. Spring-04-Spring的入门配置
  19. Java工程师初学Android(四)(转)
  20. 服务器宠物系统,你们升级我抓宠,PVX也能从剑网三怀旧服的升级热潮中找到快乐!...

热门文章

  1. 2022-2028年中国帘子布行业市场研究及前瞻分析报告
  2. 2022-2028年中国高粘保护膜行业市场专项调研及发展趋势分析报告
  3. 2022-2028年中国高阻隔片材基膜行业市场供需形势及前瞻分析报告
  4. Linux shell 学习笔记(11)— 理解输入和输出(标准输入、输出、错误以及临时重定向和永久重定向)
  5. Tengine MLOps概述
  6. Recommenders with TensorRT
  7. 2021年大数据ELK(十六):Elasticsearch SQL(职位查询案例)
  8. Lumen报class does not exist的mailer坑
  9. CSS 选择器:BeautifulSoup4解析器
  10. CSS Modules