[新星计划] Python上下文管理器 | with关键字

Posted cPen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[新星计划] Python上下文管理器 | with关键字相关的知识,希望对你有一定的参考价值。


系列文章
https://blog.csdn.net/cpen_web/category_11089219.html


● 介绍

上下文管理器是装饰器的近亲,与装饰器类似的,它们都是包装其他代码的工具
○ 装饰器:包装用于定义的代码块
○ 上下文管理器:可以包装任意格式的代码块

上下文管理器是一个包装任意代码块的对象,上下文管理器保证:
○ 进入上下文管理器时,每次代码执行的一致性
○ 当退出上下文管理器时,相关的资源会被正确地回收(即使内部代码出错,退出步骤也执行)

上下文管理器的应用
○ 上下文管理器被用到最多的就是——作为确保资源正确清理的一种方式


● 语法

with语句
○ python2.5中加入的关键字with
○ with语句仅仅能对支持上下文管理协议的对象使用
○ with语句的表达式的作用是返回一个遵循特定协议的对象,具体来说,该对象必须定义一个__enter__方法和__exit__方法

with语句执行的解析
○ 语法:with context_expr as cm: do_sth()
○ 当with语句执行时,便执行上下文表达式(context_expr)来获得一个上下文管理器对象,上下文管理器的职责是提供一个上下文对象,用于在with语句块中处理细节:
      ○ 一旦获得了上下文对象,就会调用它的__enter__()方法
      ○ 将完成with语句块执行前的所有准备工作
      ○ 如果with语句后面跟了as语句,方法返回的结果会被赋值给as关键字后面的变量
      ○ 除了self参数,__enter__方法不接受任何其他参数
      ○ __enter__方法一般负责执行一些配置

# 示例:上下文管理器 基本语法

# 1、普通方法打开文件对象
fp = open("test.txt","a+")  # a+ 追加写
print(dir(fp))
#结果为 [ …'__enter__', …, '__exit__'…]
#注:有__enter__、__exit__方法,是上下文管理器
fp.write("this is test")
fp.close()  #注:处理结束后,把它关掉,不然占资源

# 2、用with语句执行
with open("test.txt","a+") as f:    #注:赋给f对象
    f.write("write test")
    #退出语句执行之后 with自动回收对象
    #因为打开的文件对象是上下文管理器
    #注:open("test.txt","a+"):上下文表达式

with语句执行的解析
○ 当with语句块结束时,无论是正常结束,还是由于异常,都会调用上下文对象的__exit__()方法
      ○ __exit__()方法有3个参数
      ○ 如果with语句正常结束,三个参数全部都是 None
      ○ 如果发生异常,三个参数的值分别等于调用sys.exc_info()函数返回的三个值:类型(异常类)、值(异常实例)和跟踪记录(traceback),相应的跟踪记录对象
      ○ 因为上下文管理器主要作用于共享资源,__enter__()和__exit__()方法基本是完成的是分配和释放资源的低层次工作,比如:数据库连接、锁分配、信号量加/减、状态管理、文件打开/关闭、异常处理等


● 异常处理

上下文管理器必须定义__exit__方法,该方法可以选择性地处理包装代码块中出现的异常,或者处理其他需要关闭上下文状态的事情

__exit__方法接收了异常信息,就有处理这个异常的义务,通常可以做以下几件:
○ 传播异常
○ 中止异常
○ 抛出不同异常

# 示例:__exit__
#__exit__ 接受三个参数  异常类,异常值,回溯信息

#上下文管理器  传播异常  终止异常

class MyException():
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_val: #注:如果有异常发生
            print(f"My exception: {exc_val}")
        # return False   #注:传播异常,给解释器识别
        return True      #注:中止异常

with MyException():#使用上下文管理器
    print(1+1)  #注:没有异常,输出为2
with MyException():
    print(1/0)  #注:False时 有异常
#False时 结果为 My exception: division by zero
#True时 结果为
# My exception: division by zero	#注:True时  不报错,程序不中断
#注:True时 把异常传递出去,给解释器知道

print("end......")
#注:return False 不会执行 end......
#注:return True  执行了   end......
# 示例:如果是ValueError异常,终止异常;如果不是,传播异常
class MyException():
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        if issubclass(exc_type, ValueError): #注:如果是ValueError异常及子类异常
        # if exc_type == ValueError:  #注:exc_type是类,所以判断条件ValueError类
            return True #终止异常
        return False    #传播异常

with MyException():
    print(1+1)
    raise ValueError("test value error")

#注:issubclass(exc_type, ValueError) 如果是ValueError异常及子类异常

● contextlib模块

contextlib模块介绍
○ contextlib模块实现上下文自动管理
○ 这个生成器可以用更简单的方法创建上下文管理器

# 示例:contextlib实现上下文管理器
import contextlib

@contextlib.contextmanager
def mycontext():
    print("enter context")
    yield   #注:生成器函数
    print("exit context")

c1 = mycontext()
print(dir(c1))
#结果为 […'__enter__',  '__exit__'…]
#注:使用装饰器后 就是上下文管理器了。不使用装饰器,只是生成器对象

with c1:
    print("xxxxxxxxxx")
#结果为
# enter context
# xxxxxxxxxx
# exit context

pic1

北漂生活 。。。

觉得写的不错的话,欢迎点赞+评论+收藏。


以上是关于[新星计划] Python上下文管理器 | with关键字的主要内容,如果未能解决你的问题,请参考以下文章

[新星计划] Python上下文管理器 | with关键字

[新星计划] Python内存管理 | 引用计数垃圾回收内存池机制

[新星计划] Python内存管理 | 引用计数垃圾回收内存池机制

[新星计划] Python内存管理 | 引用计数垃圾回收内存池机制

[新星计划] Python面向对象练习 | 回合制对战游戏模拟ATMLinux用户管理类

[新星计划] Python面向对象练习 | 回合制对战游戏模拟ATMLinux用户管理类