什么是上下文管理器

官方解释...

  • 上下文管理器是一个对象
  • 它定义了在执行 with 语句时要建立的运行时上下文
  • 上下文管理器处理进入和退出所需的运行时上下文以执行代码块
  • 上下文管理器通常使用 with 语句调用,但也可以通过直接调用它们的实例方法来使用

一顿花里胡哨猛如虎,结果我也不太懂

简单一句话

同时包含 __enter__() 和 __exit__() 方法的对象就是上下文管理器

__enter__(self)

  • 进入上下文管理器自动调用的方法
  • 该方法会在 with ... as ... 代码块执行之前执行
  • 如果 with 语句有 as 子句,且该方法有返回值,那么该方法的返回值会被赋值给 as 子句后的变量,最常见的 with open('file_path', 'w') as file:
  • 该方法可以返回多个值,因此在 as 子句后面也可以指定多个变量(多个变量必须由“()”括起来组成元组)

__exit__(self, exc_type, exc_value, exc_traceback)

  • 退出上下文管理器自动调用的方法,会返回一个布尔类型的值
  • 该方法会在 with ... as ... 代码块执行之后执行
  • 如果 with ... as ... 代码块成功执行结束,程序自动调用该方法,且三个参数都为 None
  • 如果 with ... as ... 代码块执行时发生异常,通过 sys.exc_info() 得到异常信息,三个参数值分别是:异常类型、异常信息、异常回溯信息类型

有哪些常见上下文管理器?

打开文件

with open('file_path', 'w') as file:
file.write('hello world !')

拆分了解

  • 上下文表达式: with open('file_path', 'w') as file:
  • 上下文管理器: open('file_path', 'w')
  • file:可以理解为资源对象

执行顺序

  1. 先执行 open() 的 __enter__() 方法,将返回值赋值给 file
  2. 执行 file.write('hello world !')
  3. 最后执行 open() 的 __exit__() 方法

自定义上下文管理器

其实有两种方式

  1. 基于类实现
  2. 基于生成器实现

基于类实现上下文管理器

只需要给对象添加一个 __enter__ 和一个 __exit__ 方法

import sys

class Resource:
def __init__(self, name):
self.name = name
print("== 初始化方法 ==") def __enter__(self):
print(f"** 进入上下文管理器自动调用:name is {self.name}")
# 可以返回任意类型的值
return {"name": self.name} def __exit__(self, exc_type, exc_val, exc_tb):
print(f"## 退出上下文管理器自动调用:", sys.exc_info(), exc_type, exc_val, exc_tb)
if exc_tb is None:
print("没有异常时关闭资源")
else:
print("遇到异常时关闭资源")

通过 with 来调用该上下文管理器

也称为:使用 with ... as ... 管理资源

with Resource("小菠萝") as r:
print(r)

console 输出结果

== 初始化方法 ==
** 进入上下文管理器自动调用:name is 小菠萝
{'name': '小菠萝'}
## 退出上下文管理器自动调用: (None, None, None) None None None
没有异常时关闭资源

__exit__() 方法的三个参数值都是 None

with 代码块抛出异常

with Resource("异常小菠萝") as r:
print('[with代码块] 异常之前的代码')
raise Exception("抛出了 Exception")
print('[with代码块] ~~~~~~~~异常之后的代码')

console 输出结果

== 初始化方法 ==
** 进入上下文管理器自动调用:name is 异常小菠萝
[with代码块] 异常之前的代码
## 退出上下文管理器自动调用: (<class 'Exception'>, Exception('抛出了 Exception'), <traceback object at 0x10e203200>) <class 'Exception'> 抛出了 Exception <traceback object at 0x10e203200>
遇到异常时关闭资源
Traceback (most recent call last):
File "/Users/polo/Documents/pylearn/第七章:文件相关/1_上下文管理器.py", line 36, in <module>
raise Exception("抛出了 Exception")
Exception: 抛出了 Exception 

代码块抛出异常的时候,可以看到 __exit__() 方法的三个参数值的确来源于 sys.exc_info()

总结

  • 无论 with 代码块是否有异常,最终都会自动调用 __exit__() 方法
  • 当抛出异常时,__exit__() 默认返回 None,会重新抛出异常到外面,让 with ... as ... 以外的代码来处理异常
  • 反之,如果返回 True,就会忽略异常,不再对异常进行处理

__exit__() 返回 True

    def __exit__(self, exc_type, exc_val, exc_tb):
print(f"## 退出上下文管理器自动调用:", sys.exc_info(), exc_type, exc_val, exc_tb)
if exc_tb is None:
print("没有异常时关闭资源")
else:
print("遇到异常时关闭资源")
return True # 再次运行
with Resource("异常小菠萝") as r:
print('[with代码块] 抛出异常之前的代码')
raise Exception
print('[with代码块] 抛出异常之后的代码')

console 输出结果

== 初始化方法 ==
** 进入上下文管理器自动调用:name is 异常小菠萝
[with代码块] 异常之前的代码
## 退出上下文管理器自动调用: (<class 'Exception'>, Exception('抛出了 Exception'), <traceback object at 0x100e29200>) <class 'Exception'> 抛出了 Exception <traceback object at 0x100e29200>
遇到异常时关闭资源

不再抛出异常

基于生成器实现上下文管理器

通过装饰器 contextlib.contextmanager,来定义自己所需的基于生成器的上下文管理器

from contextlib import contextmanager

@contextmanager
def file_manager(name, mode):
try:
# 1、打开文件
file = open(name, mode)
# 2、返回文件资源对象
yield file
finally:
# 3、关闭文件
file.close() with file_manager('a.txt', 'w') as file:
print(file)
file.write('hello world')
  • 函数 file_manager() 就是一个生成器
  • 当执行 with as 语句时,获取文件资源对象,生成器暂停执行,返回文件资源对象并赋值给 file
  • 当 with 语句执行完后,生成器继续执行剩余代码,关闭文件,释放资源

总结

  • 基于生成器的上下文管理器时,不再用定义 __enter__() 和 __exit__() 方法
  • 但需要加上装饰器 @contextmanager

with 语句的教程

https://www.cnblogs.com/poloyy/p/15335965.html

Python - Context Manager 上下文管理器的更多相关文章

  1. (转)Python中的上下文管理器和Tornado对其的巧妙应用

    原文:https://www.binss.me/blog/the-context-manager-of-python-and-the-applications-in-tornado/ 上下文是什么? ...

  2. Python深入02 上下文管理器

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...

  3. Python中的上下文管理器和with语句

    Python2.5之后引入了上下文管理器(context manager),算是Python的黑魔法之一,它用于规定某个对象的使用范围.本文是针对于该功能的思考总结. 为什么需要上下文管理器? 首先, ...

  4. 【Python】【上下文管理器】

    """#[备注]#1⃣️try :仅当try块中没有异常抛出时才运行else块.#2⃣️for:仅当for循环运行完毕(即for循环没有被break语句终止)才运行els ...

  5. 深入理解 Python 中的上下文管理器

    提示:前面的内容较为基础,重点知识在后半段. with 这个关键字,对于每一学习Python的人,都不会陌生. 操作文本对象的时候,几乎所有的人都会让我们要用 with open ,这就是一个上下文管 ...

  6. python中实现上下文管理器的两种方法

    上下文管理器: python中实现了__enter__和__exit__方法的对象就可以称之为上下文管理器 实现方法一举例: def File(object): def __init__(self, ...

  7. Python异常处理与上下文管理器

    Python异常处理 异常与错误 错误 可以通过IDE或者解释器给出提示的错误opentxt('a.jpg','r') 语法层面没有问题,但是自己代码的逻辑有问题if age>18: print ...

  8. python中利用上下文管理器来实现mysql数据库的封装

    from pymysql import connect class DB(object): def __init__(self, password, database): # 1.连接数据库 self ...

  9. python中的上下文管理器

    刚刚看了vamei大神的上下文管理器博客,理解如下: 其实我自己经常用到上下文管理器,尤其是在打开文件的时候,如果自己比较懒,不想手工打上f.close(),使用上下文管理器就ok拉. 上下文管理器就 ...

随机推荐

  1. .NET 元数据概述

    元数据是一种二进制信息,用以对存储在公共语言运行库可移植可执行文件 (PE) 文件或存储在内存中的程序进行描述.将您的代码编译为 PE 文件时,便会将元数据插入到该文件的一部分中,而将代码转换为 Mi ...

  2. C#中的信号量---Semaphore

    emaphore是System.Threading下的类,限制可同时访问某一资源或资源池的线程数. 常用构造方法 https://msdn.microsoft.com/zh-cn/library/e1 ...

  3. 解析一个HTML字符串

    存在问题 来自用户输入,一个文件或一个网站的HTML字符串,你可能需要对它进行解析并取其内容,或校验其格式是否完整,或想修改它.怎么办?jsonu能够帮你轻松解决这些问题 解决方法 使用静态Jsoup ...

  4. LeetCoded第25题题解--K个一组翻转链表--java--链表

    链表 单链表:链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素的引用字段链接在一起. 双链表:与单链表不同的是,双链表的每个节点都含有两个引用字段. 链表优点 灵活分配内存空间 能在O ...

  5. urllib3中学到的LRU算法

    介绍 urllib3._collections.py::RecentlyUserContainer类,是一个线程安全的Dict类容器,用来维护一定数量(maxsize)的Key-Value映射, 当数 ...

  6. ❤️用武侠小说的形式来阅读LinkedList的源码,绝了!

    一.LinkedList 的剖白 大家好,我是 LinkedList,和 ArrayList 是同门师兄弟,但我俩练的内功却完全不同.师兄练的是动态数组,我练的是链表. 问大家一个问题,知道我为什么要 ...

  7. CSS布局中最小高度的妙用

    CSS布局中最小高度的妙用 --最小高度可以设定一个BOX的最小高度,当其内容较少时时,也能保持BOX的高度为一定,超出就自动向下延伸最小高度可以设定一个BOX的最小高度,当其内容较少时时,也能保持B ...

  8. Python之requests模块-session

    http协议本身是无状态的,为了让请求之间保持状态,有了session和cookie机制.requests也提供了相应的方法去操纵它们. requests中的session对象能够让我们跨http请求 ...

  9. docker入门及常用命令

    Docker简介 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布 ...

  10. 羽夏笔记——Win32(非WinAPI)

    写在前面   本笔记是由本人独自整理出来的,图片来源于网络.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你 ...