• 上下文管理器——with语句的实现


    前言

    with语句的使用给我们带来了很多的便利,最常用的可能就是关闭一个文件,释放一把锁。

    既然with语句这么好用,那我也想让我自己写的代码也能够使用with语句,该怎么实现?

    下面具体介绍怎样实现一个自己的with语句

    使用类实现

    要想使用with语句,那就要遵循with语句的使用规矩,也就是上下文管理器协议

    这个协议提示我们要在类中去实现两个特殊方法,enter(self)和exit(self, exc_type, exc_val, exc_tb)

    有了这两个方法,就可以使用with语句执行了,它的执行过程为先执行enter(self)方法,然后执行你添加在with下的代码,然后最后执行exit方法

    如果在执行的过程中出现了异常,那么会自动执行exit方法,

    
    class ErrorProduce:
        def __init__(self):
            pass
    
        def produce(self):
            raise RuntimeError('ERROR')
    
    class MyWith:
        def __enter__(self):
            return ErrorProduce()
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            if exc_type:
                print("有错")
                #print(exc_val)
                #return True
            else:
                print("完美执行")
    
    with MyWith() as E:
        E.produce()
    

    将上述代码运行,会先打印出“有错”,然后再打印出相关错误,然后程序由于错误终止,也就是说,在产生了错误后,还是执行了exit中的代码

    如果将exit中的两个注释符号去掉的话,那么再次运行程序不会报错,但会将exc_val中的错误信息打印出来,这里相当于通过exit方法将错误抹除掉了,抹除方式为返回True,但也把with中抛出错误后的所有代码都跳过了。

    使用函数实现

    通过引入contextlib模块中的contextmanager装饰器,装饰函数使函数可以使用with语句

    
    from contextlib import contextmanager
    
    class ErrorProduce:
        def __init__(self):
            pass
    
        def produce(self):
            raise RuntimeError('ERROR')
    
    @contextmanager
    def my_with():
        try:
            yield ErrorProduce()
        except Exception as e:
            print(e)
         #raise
        finally:
            print('收尾')
    
    with my_with() as E:
        E.produce()
        print('aa')
    

    函数中使用了yield,那么它也就变成了生成器,通过yield来划分相当于类中的enter和exit,yield返回的值也就是可以用作as后的值

    上段代码中我们发现使用了try,except,finally异常处理的语句,这些语句是必要的吗?

    通过测试,如果没有这些异常处理,那么with语句还是可以执行的,这里的意思是可以使用with语句,不会报不能使用with的错误,但是使用后,只有with下的语句中没有抛出异常,那么yield语句后边的代码才会执行,一旦有异常抛出,仍然是程序运行终止。所以,一般还是要配合try,except,finally语句来构造。

    还有一点要注意,使用这种方式,异常被except捕捉后,那么这个异常就失效了,一般的我们还是会需要在except中再次将捕捉的异常抛出,也就是在后面加上raise,因为我们使用with只是为了做好一个收尾,如关闭文件句柄。或者另一种方式,我们干脆就不写except语句,直接写finally语句了。


    • 文章中出现的棕色加粗的单词,是由于markdown-here将特殊方法两边的下划线转换产生的,原意为特殊方法
  • 相关阅读:
    虚方法表与动态分派机制
    方法重载与invokevirtual字节码指令的关系
    栈桢与操作数栈以及符号引用与直接引用的转换
    通过字节码分析this关键字以及异常表的作用
    JVM synchronized关键字所生成的字节码
    window Chrome 下允许跨域访问服务端接口设置
    JVM Java字节码方法表与属性
    JVM 字节码的结构
    Jar hell问题以及解放方法
    JVM 线程上下文类加载器
  • 原文地址:https://www.cnblogs.com/sfencs-hcy/p/10125534.html
Copyright © 2020-2023  润新知