with 语句使用于对资源进行访问的场合,确保不管使用过程是否发生异常都会执行必要的"清理"操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放
with open("1.txt") as file:
data = file.read()
使用with,能够减少冗长,还能自动处理上下文环境产生的异常
with 工作原理
(1)紧跟with后面的语句被求值后,返回对象的__enter__()
方法被调用,这个方法的返回值将被赋值给as后面的变量;
(2)当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()
方法。
with工作原理代码示例:
class Sample:
def __enter__(self):
print("进入 with")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出 with")
def xxx(self):
print('读取文件')
with Sample() as sample:
print("__enter__的返回值: ", sample)
sample.xxx()
结果
进入 with
__enter__的返回值: <__main__.Sample object at 0x000001B6C33977F0>
读取文件
退出 with
可以看到,整个运行过程如下:
(1)__enter__()
方法被执行;
(2)__enter__()
方法的返回值,在这个例子中是self
,赋值给变量sample;
(3)执行代码块,__enter__的返回值: <__main__.Sample object at 0x000001B6C33977F0>
;
( 4 )执行方法 xxx()
( 5 )__exit__()
方法被调用;
【注:】exit()方法中有3个参数, exc_type, exc_val, exc_tb,这些参数在异常处理中相当有用。
exc_type: 错误的类型
exc_val: 错误类型对应的值
exc_tb: 代码中错误发生的位置
总结
实际上,在with后面的代码块抛出异常时,exit()方法被执行。开发库时,清理资源,关闭文件等操作,都可以放在exit()方法中。
总之,with-as表达式极大的简化了每次写finally的工作,这对代码的优雅性是有极大帮助的。
如果有多项,可以这样写:
With open('1.txt') as f1, open('2.txt') as f2:
do something