with 语句是 Pyhton 上的一种简化语法,with 语句是从 Python 2.5 开始引入的一种与异常处理相关的功能。with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必需的“清理”操作,释放资源。比如文件使用后自动关闭、数据库的打开和自动关闭等。
语法格式是这样的:

with open('test', 'w') as f:
    f.write('Python大法好')

通过 with 语句在编写代码时,会使代码变得更加简洁。在编写代码时,不用再显示的去关闭文件。
语句的执行过程:
1.在执行 with 语句时,首先执行 with 后面的 open 代码
2.执行完代码后,会将代码的结果通过 as 保存到 f 中
3.然后在下面实现真正要执行的操作
4.在操作后面,并不需要写文件的关闭操作,文件会在使用完后自动关闭

实际上,在文件操作时,并不是不需要写文件的关闭,而是文件的关闭操作在 with 的上下文管理器中的协议方法里已经写好了。
当文件操作执行完成后, with语句会自动调用上下文管理器里的关闭语句来关闭文件资源。

with 语句在执行时,需要调用上下文管理器中的 enterexit 两个方法。
enter 方法会在执行 with 后面的语句时执行,一般用来处理操作前的内容。比如一些创建对象,初始化等。
exit 方法会在 with 内的代码执行完毕后执行,一般用来处理一些善后收尾工作,比如文件的关闭,数据库的关闭等。
在自定义上下文管理器时,只需要在类中实现 enterexit 两个方法即可。
模拟文件打开过程:

import time


class MyOpen(object):
    def __init__(self,file, mode):
        self.__file = file
        self.__mode = mode

    def __enter__(self):
        print('__enter__ run ... 打开文件')
        self.__handle = open(self.__file, self.__mode)
        return self.__handle

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__... run ... 关闭文件')
        self.__handle.close()


with MyOpen('test','w') as f:
    f.write('Python 大法好')
    time.sleep(3)

print('over')

程序执行结果:

__enter__ run ... 打开文件
__exit__ run ... 关闭文件
over

exit 方法中有三个参数,用来接收处理异常,如果代码在运行时发生异常,异常会被保存到这里。

  • exc_type : 异常类型
  • exc_val : 异常值
  • exc_tb : 异常回溯追踪
    异常信息的处理
    当with中执行的语句发生异常时,异常信息会被发送到 exit 方法的参数中,这时可以根据情况选择如何处理异常。
class MyCount(object):
    def __init__(self, x, y):
        self.__x = x
        self.__y = y

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 通过 参数接收到的值,来判断程序执行是否出现异常
        # 如果是 None ,说明没有异常
        if exc_type == None:
            print('计算正确执行')
        else:
            # 否则出现异常,可以选择怎么处理异常
            print(exc_type,exc_val)
        # 返回值决定了捕获的异常是否继续向外抛出
        # 如果是 False 那么就会继续向外抛出,程序会看到系统提示的异常信息
        # 如果是 True 不会向外抛出,程序看不到系统提示信息,只能看到else中的输出
        return True

    def div(self):
        print(self.__x / self.__y)


with MyCount(6, 0) as mc:
    mc.div()

在 __exit__函数执行异常处理时,会根据函数的返回值决定是否将系统抛出的异常继续向外抛出。

如果返回值为 False 就会向外抛出,用户就会看到。 如果返回值为 True 不会向外抛出,可以将异常显示为更加友好的提示信息。