043.Python异常处理_自定义上下文管理器

发布时间:2023年12月20日

无奋斗不青春

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈

分隔线

自定义上下文管理器

  • 实际上就是创建一个类,实现__enter__()(进入)方法和__exit__()(退出)方法
  • __enter__()(进入)方法中执行一些准备操作
  • __exit__()(退出)方法会接收到语句体执行时抛出的异常类型、异常的值和追踪信息
  • 示例
    # 自定义上下文管理器
    class Test:
        def __enter__(self):
            print('enter方法')
            return 'enter方法的返回值'
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            """
            exc_type:异常类型
            exc_val:异常的值
            exc_tb:追踪信息对象Traceback
            """
            print('exit方法', exc_type, exc_val, exc_tb)
    
    
    # 使用自定义上下文管理器
    with Test() as x:
        print(x)
        1 / 0
    
    
    
    # ============输出结果============
    # enter方法
    
    # enter方法的返回值
    
    # exit方法 <class 'ZeroDivisionError'> division by zero <traceback object at 0x000002009555F400>
    
    # Traceback (most recent call last):
    #   File "E:\StudyCode\Python\14-异常处理\03-自定义上下文管理器.py", line 12, in <module>
    #     1 / 0
    # ZeroDivisionError: division by zero
    
  • 示例解析
    # with 后面的 Test() 是创建一个类实例对象-上下文管理器
    # 自动执行上下文管理器对象内部的 __enter__() 方法
        # 比如文件操作的 open(),就可以把文件打开操作放到 __enter__() 方法内部
    # 执行完 __enter__() 方法,会把这个方法的返回值赋值给 with 语句中 as 后面的变量 x
    # 执行语句体: print(x) 和 1 / 0
    # 最后自动执行上下文管理器对象内部的 __exit__() 方法,这个方法会接收到语句体抛出的异常(包含:异常类型、异常值和追踪信息对象)
    # __exit__() 方法的返回值为 True 则不会再将接收到的异常往外抛出,如果返回值为 False 则将接收到的异常继续往外抛出
    # 所有最后的清理操作都可以写到 __exit__() 方法中(比如文件操作中最后的关闭文件操作)
    
  • __exit__()方法中接收到的追踪信息对象,我们也可以获取到对象的相关信息
    # 自定义上下文管理器
    class Test:
        def __enter__(self):
            # print('enter方法')
            return 'enter方法的返回值'
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            """
            exc_type:异常类型
            exc_val:异常的值
            exc_tb:追踪信息对象
            """
            # print('exit方法', exc_type, exc_val, exc_tb)
            
            # 获取追踪信息对象的内容
            import traceback
            print(traceback.extract_tb(exc_tb))
            
            return True
    
    
    # 使用自定义上下文管理器
    with Test() as x:
        # print(x)
        1 / 0
        
        
    # ========== 输出结果 ==========
    # [<FrameSummary file E:\StudyCode\Python\14-异常处理\03-自定义上下文管理器.py, line 22 in <module>>]
    

contextlib模块

@contextlib.contextmanager装饰器

  • 作用
    • 使用装饰器,让生成器变成上下文管理器
  • 知识回顾
    • 生成器:包含 yield 语句的函数,这个函数的执行结果就是“生成器”
    • 关于生成器
    def Test():
        print('Text函数', 1)
        yield '返回值1'
        print('Text函数', 2)
    
  • 使用装饰器,让生成器变成上下文管理器
    import contextlib
    
    @contextlib.contextmanager
    def Test():
        print('Text函数', 1)
        yield '返回值1'
        print('Text函数', 2)
    
    
    with Test() as x:
        2 / 1
        print(x)
        
    
    # ========== 输出结果 ==========
    # Text函数 1
    # 返回值1
    # Text函数 2
    
  • 执行分解
    • 使用@contextlib.contextmanager装饰之后
    • yield之前的语句就是上下文管理器中的__enter__方法
    • yield语句就是执行 语句体
    • yield之后的语句就是上下文管理器中的__exit__方法
  • 应用示例
    import contextlib
    
    @contextlib.contextmanager
    def Test():
        try:
            yield
        except Exception as e:
            print('异常:', e)
    
    
    with Test() as x:
        2 / 0
    
    
    # ========== 输出结果 ==========
    异常: division by zero
    
    
    # 步骤解析
    # try语句写在yield之前,会先执行
    # 通过yield语句执行语句体 2/0,会抛出异常
    # 执行yield后面的except语句捕获异常
    

contextlib.closing函数

  • 作用
    • 使用函数,让拥有close()方法但不是上下文管理器的对象变成上下文管理器
    • 注意:这个对象中必须要有close()方法,而且是要求最后必须执行close()方法
  • 通过案例讲解
    • 有一个如下的类对象
      class Test:
          def tt(self):
              print('tt方法')
      
          def close(self):
              print('对象关闭,释放资源')
      
    • 使用需求:Test类实例对象每次调用完tt()方法后,都需要执行close()方法关闭对象,释放资源
    • 按照我们刚学的上下文管理器进行操作,就需要再Test类当中增加__enter__()__exit__()两个方法
      class Test:
          def tt(self):
              print('tt方法')
      
          def close(self):
              print('对象关闭,释放资源')
      
          def __enter__(self):
              return self
      
          def __exit__(self, exc_type, exc_val, exc_tb):
              self.close()
      
      
      # 要求:Test类实例对象每次调用完tt()方法后,都需要执行close()方法关闭对象,释放资源
      with Test() as x:
          x.tt()
      
      # ========== 输出结果 ==========
      # tt方法
      # 对象关闭,释放资源
      
      
      # 解析:为什么要在__enter__中返回一个self
      # 因为我们需要在with语句里面去执行实例方法tt(),所以我们需要拿到这个实例对象
      # 通过__enter__方法使用self将这个实例对象返回,就可以将这个实例对象赋值给with语句中的x
      # 再通过 x 去调用实例方法 tt()
      
    • 这样写的话,就每次都要添加__enter__()__exit__()两个方法,比较麻烦
    • 我们可以通过contextlib.closing()函数来解决这个问题
      class Test:
          def tt(self):
              print('tt方法')
      
          def close(self):
              print('对象关闭,释放资源')
      
      
      # 要求:Test类实例对象每次调用完tt()方法后,都需要执行close()方法关闭对象,释放资源
      
      import contextlib
      
      with contextlib.closing(Test()) as x:
          x.tt()
      
    • 只需要在with语句中使用contextlib.closing()函数就能达到上面增加__enter__()__exit__()两个方法的效果

contextlib.nested函数(Python3.x 已弃用)

  • contextlib.nested()函数在Python3.x中已经已弃用,仅做了解即可!
  • 作用
    • 在Python2.7版本之前,完成多个上下文管理器的嵌套
  • 通过案例讲解
    • 需求:读取一个文件所有内容,再把内容写入到另一个文件中
    • 在Python2.7版本之前的写法
    with open('xx.jpg', mode='rb') as form_file:
        with open('xx2.jpg',mode = 'wb') as to_file:
            file_content = form_file.read()
            to_file.write(file_content)
    
    • 这样写的话,就需要用到多个open()对象的上下文管理器做嵌套
    • 在Python2.7之前,就可以用contextlib.nested()函数来处理
    import contextlib
    
    with contextlib.nested(open('xx.jpg', mode='rb'), open('xx2.jpg', mode='wb')) as (form_file,to_file):
        file_content = form_file.read()
        to_file.write(file_content)
    
    • 但是,在Python3.x版本对这种多个上下文管理器的嵌套进行了优化,也不在需要用contextlib.nested函数了
    with open('xx.jpg', mode='rb') as form_file, open('xx2.jpg', mode='wb') as to_file:
        file_content = form_file.read()
        to_file.write(file_content)
    
    • 关于这个函数我们只需要了解一下就行,记住Python3.x版本的写法即可
文章来源:https://blog.csdn.net/weixin_50296259/article/details/135060727
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。