六、Python IO与异常 之 4、with语句

4、with语句

说明:with 语句管理资源关闭

with open('data.txt', 'r', True, 'GBK') as f:    # 把打开文件放在 with 语句中,可自动关闭文件
    print(f.read())
第一行
第二行
第三行

原理

  • 使用 with 语句管理的资源必须是一个实现上下文管理协议(context manage protocol)的类。

  • 实现上下文管理协议必须实现两个方法:

    • context_manager._enter_():进入上下文管理器自动调用该方法。

      • 该方法会在 with 代码块执行之前执行;
      • 若 with 语句有 as子句,那么该方法的返回值会被赋值给 as 子句后的变量;
      • 该方法可以返回多个值,因此 as 子句后可指定多个变量(多个变量必须由“()”括起来组成元组)。
    • context_manger._exit_(exc_type, exc_value, exc_traceback):退出上下文管理器自动调用方该方法。

      • 该方法会在 with 代码块执行之后执行;

      • 若 with 代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为 None;

      • 若 with 代码块因为异常而中止,程序也自动调用该方法,使用 sys.exc_info 得到的异常信息将作为调用该方法的参数(可使用 help(sys.exc_info) 查看该函数说明)。

        • ex_type:异常类型
        • ex_value:异常值,创建异常时传入的所有参数值
        • ex_traceback:异常的traceback对象,包含出错的行数、位置等数据。
        import traceback
        import sys
        try:
             raise ValueError(10, '抛出异常')    # 10 为自定义的异常编号
        except Exception as ex:
            ex_type, ex_value, ex_traceback = sys.exc_info()
            print(ex_type)
            print(ex_value)
            for stack in traceback.extract_tb(ex_traceback):
                print(stack)
        
        <class 'ValueError'>
        (10, '抛出异常')
        <FrameSummary file test.py, line 4 in <module>>
        

分析

  • 一个类实现了 __enter__() 和 __exit__(exc_type, exc_value, exc_traceback) 方法,程序就可以使用 with 语句来管理它;
  • 通过 __exit__() 方法的参数,即可判断出 with 代码块执行时是否遇到了异常
class FkResource:
    def __init__(self, tag):
        self.tag = tag
        print('---构造方法---')
        
    # 进入with 语句时会执行该方法
    def __enter__(self):
        print('该资源的tag:', self.tag)
        return 'python'       # 此处的返回值就是 as 语句中变量的值
 
    def __exit__(self, ex_type, ex_value, ex_traceback):
        if ex_traceback:      # ex_traceback 若存在,说明因为异常退出
            print('出现异常(关闭资源)')
        else:
            print('正常结束(关闭资源)')
with FkResource('java') as fk:
    print('fk为:', fk)
    print('before')
    print('活动')
    print('after')
---构造方法---
该资源的tag: java
fk为: python
before
活动
after
正常结束(关闭资源)
with FkResource('java') as fk:
    print('fk为:', fk)
    print('before')
    raise Exception(10, '自定义异常')
    print('after')
---构造方法---
该资源的tag: java
fk为: python
before
出现异常(关闭资源)
--------------------------------------
...(省略)
Exception: (10, '自定义异常')

分析:步骤如下。

  1. 执行 with 子句后的表达式(FkResource(‘java’))
  2. 执行__enter__方法,并将改方法的返回值赋值给as子句中的变量
  3. 在 with 语句块完成或遇到异常时自动执行__exit__方法
上一篇:java学习之路--面试之多线程基础


下一篇:[集训]FWT基础练习题