首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Python中的上下文管理器:使用with管理成对操作,初级及高级用法解析

  • 25-04-24 08:01
  • 4198
  • 5817
blog.csdn.net

目录

1. 前言

2. 最最基本的一个上下文管理器

3. 自定义上下文管理器基本用法

4. 上下文管理器的高级用法

4.1 通过生成器函数实现上下文管理( contextlib 模块)

4.2 处理异常

4.3 嵌套使用上下文管理器

5. 总结


1. 前言

在 Python 中,资源管理是一个至关重要的主题。无论是文件操作、数据库连接,还是网络请求等场景,我们都需要确保资源被正确地获取和释放,以避免资源泄漏、数据损坏等问题。而 Python 的上下文管理器,能够帮助我们精准地掌控这些成对的操作,让代码不仅更加简洁,而且更具健壮性和可维护性。

在阅读此文前需明白魔法方法概念以理解__enter__和__exit__,请阅读以下这篇博客:

《python中的对魔法方法的理解,__call__、__add__、__str__、__len__、__init__等等常见魔法方法分别什么意思?》

2. 最最基本的一个上下文管理器

上下文管理器是 Python 中用于定义执行代码块之前和之后所需逻辑的工具,它允许我们使用 with 语句来创建一个临时的上下文,并在该上下文范围内执行代码。

最典型的例子就是文件操作,而我将以此构造一个最最简单的上下文管理器。

普通文件操作:

  1. f = open('test.txt')
  2. try:
  3. pass
  4. finally:
  5. f.close()

而运用上下文管理器的文件操作: 

  1. with open('test.txt') as f:
  2. pass

代码一下便是简洁直观了,在这段代码中,open 函数返回一个文件对象,这个对象就是一个上下文管理器。

有点绕,但是初步只需要知道,当我们使用 with 语句时,它会在进入代码块之前自动调用文件对象的 __enter__ 方法打开文件,并在退出代码块时自动调用 __exit__ 方法关闭文件。这样,我们就不必担心忘记关闭文件而导致资源泄漏的问题了。

3. 自定义上下文管理器基本用法

一个类要成为上下文管理器,需要实现两个特殊方法:__enter__ 和 __exit__。

__enter__ 方法会在进入 with 代码块时被调用,它通常用于获取资源、初始化对象等操作,并返回一个在代码块中使用的对象。

而 __exit__ 方法则在退出 with 代码块时被调用,用于释放资源、清理环境等工作。__exit__ 方法还可以接收异常相关的参数,这使得它能够处理在代码块中可能发生的异常情况。

举个例子,我们来创建一个简单的上下文管理器,用于测量代码块的执行时间:

  1. import time
  2. class Timer:
  3. def __enter__(self):
  4. self.start_time = time.time()
  5. return self
  6. def __exit__(self, exc_type, exc_val, exc_tb):
  7. end_time = time.time()
  8. print(f"Code block executed in {end_time - self.start_time:.4f} seconds")

使用这个上下文管理器:

  1. with Timer() as timer:
  2. # 模拟一些耗时操作
  3. time.sleep(2)

运行结果为:

在这个例子中,当进入 with 代码块时,Timer 类的 __enter__ 方法被调用,记录开始时间并返回 self。在代码块执行完毕后,__exit__ 方法被调用,计算并打印代码块的执行时间。

4. 上下文管理器的高级用法

4.1 通过生成器函数实现上下文管理( contextlib 模块)

除了手动定义类来实现上下文管理器,Python 的 contextlib 模块提供了一个装饰器 contextmanager,可以让我们更方便地创建上下文管理器。它通过生成器函数的方式,将代码分为进入上下文和退出上下文的两部分。

  1. from contextlib import contextmanager
  2. @contextmanager
  3. def my_context_manager():
  4. print("Entering the context")
  5. yield
  6. print("Exiting the context")
  7. with my_context_manager() as orange_con:
  8. print("Inside the context")

在这个例子中,my_context_manager 函数被 contextmanager 装饰。当进入 with 代码块时,函数中的代码会执行到 yield 语句之前的部分(即打印 "Entering the context"),然后将控制权交给代码块中的内容。当代码块执行完毕后,函数会从 yield 处继续执行,完成退出上下文的操作(即打印 "Exiting the context")。

4.2 处理异常

上下文管理器的 __exit__ 方法可以接收三个参数:exc_type、exc_val 和 exc_tb,分别代表异常类型、异常值和异常 traceback 信息。通过检查这些参数,我们可以在 __exit__ 方法中决定是否处理异常,或者进行一些特定的清理操作。

  1. class MyOpen:
  2. def __init__(self, filepath):
  3. print('Entering constructor of MyOpen')
  4. self.filepath = filepath
  5. def __enter__(self):
  6. print('Entering __enter__ of MyOpen')
  7. return self.filepath
  8. def __exit__(self, exc_type, exc_value, traceback):
  9. print('Entering the __exit__ of MyOpen')
  10. if exc_type is ValueError:
  11. print('Caught a ValueError')
  12. return True
  13. with MyOpen('test.txt') as f:
  14. raise ValueError('A ValueError occured')
  15. print(f'The value of f is {f}')

运行结果为:

可以看到 ,最后的  print(f'The value of f is {f}')这个语句并没有执行,那是因为返回一个错误信息后,程序直接进入__exit__方法运行,上下文管理器就到此为止了。如果想要其被执行,可以将它放在 with 块之外,或者在 with 块中使用 try...except 捕获异常。例如:

  1. with MyOpen('test.txt') as f:
  2. try:
  3. raise ValueError('A ValueError occured')
  4. except ValueError:
  5. print('Exception handled inside the with block')
  6. print(f'The value of f is {f}')

这样,即使在 with 块中抛出异常并被捕获,print 语句仍然可以执行。 

在这个例子中,当 with 代码块中抛出异常时,__exit__ 方法会捕获到异常信息,并打印出来。由于 __exit__ 方法返回了 True,所以异常不会继续向外传播,程序不会崩溃。

4.3 嵌套使用上下文管理器

在实际开发中,我们经常会遇到需要同时管理多个资源的情况,比如同时打开多个文件、连接多个数据库等。上下文管理器支持嵌套使用,我们可以使用多个 with 语句,或者利用 contextlib.ExitStack 来简化嵌套管理。

  1. with open("file1.txt", "w") as f1, open("file2.txt", "w") as f2:
  2. f1.write("Hello, File 1!")
  3. f2.write("Hello, File 2!")

或者使用 ExitStack:

  1. from contextlib import ExitStack
  2. with ExitStack() as stack:
  3. file1 = stack.enter_context(open("file1.txt", "w"))
  4. file2 = stack.enter_context(open("file2.txt", "w"))
  5. file1.write("Hello, File 1!")
  6. file2.write("Hello, File 2!")

这两种方式都可以实现对多个资源的上下文管理,选择哪种方式取决于具体的代码风格和需求。

5. 总结

Python 的上下文管理器为我们提供了一种优雅、简洁且强大的方式来管理资源的获取和释放。通过实现 __enter__ 和 __exit__ 方法,或者使用 contextlib 模块的工具,我们可以在代码块的前后自动执行特定的逻辑,确保资源被正确地管理,避免资源泄漏和异常未处理等问题。

在实际开发中,熟练掌握上下文管理器的使用,能够让我们编写出更高效、更可靠的 Python 程序。无论是处理文件、数据库连接,还是其他需要成对操作的场景,上下文管理器都值得我们深入理解和广泛应用,它是 Python 编程中不可或缺的一部分,也是提升代码质量和开发效率的利器。我是橙色小博,关注我,一起在人工智能领域学习进步。

注:本文转载自blog.csdn.net的橙色小博的文章"https://blog.csdn.net/m0_69722969/article/details/146544259"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

108
Python
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top