Python - Context Manager 上下文管理器

简介: Python - Context Manager 上下文管理器

什么是上下文管理器


官方解释...

  • 上下文管理器是一个对象
  • 它定义了在执行 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

相关文章
|
3月前
|
搜索推荐 Python
Python上下文管理器DIY指南:从入门到精通,轻松驾驭资源管理
【7月更文挑战第6天】Python的上下文管理器是资源管理的利器,简化文件操作、网络连接等场景。通过定义类及`__enter__`、`__exit__`方法,可自定义管理器,如示例中的`MyContextManager`,实现资源获取与释放。使用with语句,提升代码可读性和维护性,不仅用于基本资源管理,还可扩展到事务控制、自动重试等高级应用,让编程更加高效和灵活。
48 0
|
1月前
|
Python
Python的Virtualenv与Venv环境管理器
介绍Python的两种环境管理工具Virtualenv和venv,包括它们的安装、创建、激活、退出环境以及查看帮助信息的方法,同时对比了两者的特点和使用场景。
34 2
Python的Virtualenv与Venv环境管理器
|
1月前
|
Python
Python软件包及环境管理器conda实战篇
详细介绍了如何使用conda进行Python软件包管理及环境管理,包括查看、安装、卸载软件包,切换源,管理不同版本的Python环境,以及解决使用过程中可能遇到的错误。
61 2
Python软件包及环境管理器conda实战篇
|
2月前
|
安全 数据库连接 数据库
Python深度解析:上下文协议设计与应用技巧
在Python编程中,资源管理是一个常见且重要的问题。无论是文件操作、网络连接还是数据库事务,都需要确保资源在使用后能够正确地释放或恢复到初始状态。Python通过上下文管理器提供了一种优雅的方式来处理资源的获取与释放,使得代码更加简洁、安全。
|
3月前
|
监控 安全 数据库
逆天改命!用自定义上下文管理器,让你的Python代码效率飙升
【7月更文挑战第7天】Python上下文管理器简化资源管理,通过自定义实现优雅控制。使用with语句自动执行资源获取和释放,确保异常安全。例如,FileContextManager类通过__enter__打开文件,__exit__关闭并处理异常。自定义上下文管理器可封装重复逻辑,增强功能如日志和监控,提升代码效率与质量。利用这一工具,代码更简洁、高效且易于维护。**
29 1
|
3月前
|
程序员 数据库连接 Python
解锁Python新姿势:上下文管理器的自定义技巧,让你的编程之路更顺畅
【7月更文挑战第7天】Python上下文管理器简化资源管理,确保异常时资源正确释放。通过实现`__enter__`和`__exit__`或使用`contextmanager`装饰器自定义管理器。示例展示了类定义和装饰器方法。自定义管理器提升代码可读性,防止资源泄露,是高效编程的关键。**
35 1
|
3月前
|
安全 数据库连接 Python
告别繁琐!自定义Python上下文管理器,让你的资源管理变得如此简单
【7月更文挑战第4天】在Python中,上下文管理器通过`with`语句简化资源管理,确保资源的自动获取与释放,增强程序稳定性。自定义上下文管理器依靠`__enter__`和`__exit__`方法,例如,`CustomFileManager`类展示了如何记录文件操作。自定义管理器能简化代码、保证资源安全释放和提供定制逻辑,从而提升代码的健壮性和可维护性。它是处理文件、连接等资源管理的强大工具。
26 2
|
3月前
|
Python
告别混乱!Python上下文管理器的自定义实践,让你的代码更加整洁有序
【7月更文挑战第6天】Python的上下文管理器通过`__enter__`和`__exit__`方法自动处理资源的获取与释放,如文件操作。使用with语句结合自定义类(如`FileManager`示例),能确保文件在使用后正确关闭,防止资源泄漏,提升代码整洁度和健壮性。自定义上下文管理器是代码模块化和错误处理的好实践。
26 0
|
3月前
|
数据采集 程序员 Python
深度定制Python上下文管理器,让你的代码世界从此井井有条
【7月更文挑战第6天】Python的上下文管理器简化了资源管理,通过`__enter__`和`__exit__`方法自动处理获取和释放。例如,一个自定义的LoggingContextManager类在`__enter__`中配置日志并返回记录器,在`__exit__`中关闭文件。使用`with`语句,可以优雅地控制日志文件的生命周期,提高代码的整洁性和健壮性。
28 0
|
3月前
|
Python
惊呆了!学会这一招,你的Python上下文管理器也能玩出花样来文管理器也能玩出花样来
【7月更文挑战第6天】Python的上下文管理器是资源优雅管理的关键,与with语句结合,确保资源获取和释放。通过实现`__enter__`和`__exit__`,不仅能做资源分配和释放,还能扩展实现如计时、自动重试、事务处理等功能。例如,TimerContextManager类记录代码执行时间,展示了上下文管理器的灵活性。学习和利用这一机制能提升代码质量,增强功能,是Python编程的必备技巧。
29 0
下一篇
无影云桌面