上下文管理器


复习一下上下文管理器。我这里举例的是自定义上下文管理器。

上下文管理器

什么是上下文管理器


一个类里面有  __enter__() 和 __exit__() 方法, 就是上下文管理器.

就是执行某些 操作之前, 需要先做什么(__enter__ 方法), 然后不管这个这个正常操作需要做什么, 最后还会有一个收尾动作(__exit__ 方法)

上下文管理器示范

class TestDemo:
    def __enter__(self):
        print("are you ready?")
        # 返回self, 才可以进行链式调用
        return self

    def eating(self):
        print("eating")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("ending")



with TestDemo() as e  :
    print(e)
    e.eating()
    print("let us go !")

运行效果

are you ready?
<__main__.TestDemo object at 0x000001F743A95AF0>
eating
let us go !
ending

关于 exit 方法 的参数

exc_type,exc_val,exc_tb分别 是异常的类型, 异常的值, 异常的追踪信息

class TestDemo:
    def __enter__(self):
        print("are you ready?")
        # 返回self, 才可以进行链式调用
        return self

    def eating(self):
        print("eating")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type, exc_val, exc_tb)
        print("ending")



with TestDemo() as e  :
    print(e)
    2 / 0

运行效果

Traceback (most recent call last):
  File "E:/pythonScript/Blog/plance.py", line 20, in <module>
    2 / 0
ZeroDivisionError: division by zero
are you ready?
<__main__.TestDemo object at 0x000002A5D6F35AF0>
<class 'ZeroDivisionError'> division by zero <traceback object at 0x000002A5D6FA0440>
ending

发现这样使用, 还是会抛出异常下来

如果不想把那个异常抛出

只要在 __exit__ 的返回值里返回True 就可以了, 此时就会把这个抛出的异常给内部消化掉, 返回Fale(None) 也一样,都是抛出异常

示例代码

class TestDemo:
    def __enter__(self):
        print("are you ready?")
        # 返回self, 才可以进行链式调用
        return self

    def eating(self):
        print("eating")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type, exc_val, exc_tb)
        print("ending")
        return True



with TestDemo() as e  :
    print(e)
    2 / 0

运行效果

are you ready?
<__main__.TestDemo object at 0x00000228BF525AF0>
<class 'ZeroDivisionError'> division by zero <traceback object at 0x00000228BF9B0440>
ending

这时候,返回的报错信息,就不是红色的,而是正常的日志抛出

如果是return False 或者return 0 也是抛出异常

代码就还是上面的那个示例代码, 只是return True 改成了 return False ,运行效果如下

Traceback (most recent call last):
  File "E:/pythonScript/Blog/plance.py", line 19, in <module>
    2 / 0
ZeroDivisionError: division by zero
are you ready?
<__main__.TestDemo object at 0x000002B5EA7E5AF0>
<class 'ZeroDivisionError'> division by zero <traceback object at 0x000002B5EA8503C0>
ending

这个时候就会抛出异常

在不抛出异常的情况下,如何追踪异常信息


class TestDemo:
    def __enter__(self):
        print("are you ready?")
        # 返回self, 才可以进行链式调用
        return self

    def eating(self):
        print("eating")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("异常类型 %s" % exc_type)
        print("异常值 %s" % exc_val)
        print("异常跟踪信息 %s" % exc_tb)
        print("ending")
        return True



with TestDemo() as e  :
    print(e)
    2 / 0

这个时候运行的时候发现, 异常追踪信息给的是一个地址值

are you ready?
<__main__.TestDemo object at 0x0000016658A45AF0>
异常类型 <class 'ZeroDivisionError'>
异常值 division by zero
异常跟踪信息 <traceback object at 0x0000016658AB2440>
ending
如果我们想自己获取这个详细的异常追踪信息呢?

可以通过 traceback 这个模块, traceback.extract_tb(exc_tb) 来获取异常追踪信息

import traceback


class TestDemo:
    def __enter__(self):
        print("are you ready?")
        # 返回self, 才可以进行链式调用
        return self

    def eating(self):
        print("eating")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("异常类型 %s" % exc_type)
        print("异常值 %s" % exc_val)
        print("异常跟踪信息 %s" % exc_tb)
        print(traceback.extract_tb(exc_tb))
        print("ending")
        return True



with TestDemo() as e  :
    print(e)
    2 / 0

运行效果

are you ready?
<__main__.TestDemo object at 0x000001E000839760>
异常类型 <class 'ZeroDivisionError'>
异常值 division by zero
异常跟踪信息 <traceback object at 0x000001E000CD6280>
[<FrameSummary file E:/pythonScript/Blog/plance.py, line 25 in <module>>]
ending

文章作者: 陌上人如玉
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 陌上人如玉 !
  目录