with
语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。
with 工作原理
-
紧跟
with
后面的语句被求值后,返回对象的__enter__()
方法被调用,这个方法的返回值将被赋值给as
后面的变量。 -
当with后面的代码块全部被执行完之后,将调用前面返回对象的
__exit__()
方法。
例如:
class SqlHelper(object):
def __enter__(self):
return 123
def __exit__(self, exc_type, exc_val, exc_tb):
print("in __exit__")
# 创建Sqlhelper对象
sqlhelper = SqlHelper()
with sqlhelper as f:
print(f)
运行上面代码输出:
123
in __exit__
说明with
会首先执行 SqlHelper
类里面的__enter__()
方法,并将__enter__()
方法的返回值赋值给f
,因此打印出f
就是__enter__()
的返回值。
当执行完后,会执行__exit__()
方法。
__exit__()
方法中有3个参数, exc_type
, exc_val
, exc_tb
,这些参数在异常处理中相当有用。
- exc_type: 错误的类型
- exc_val: 错误类型对应的值
- exc_tb: 代码中错误发生的位置
例如:
class Sample():
def __enter__(self):
print('in enter')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print "type: ", exc_type
print "val: ", exc_val
print "tb: ", exc_tb
def do_something(self):
bar = 1 / 0
return bar + 10
with Sample() as sample:
sample.do_something()
运行程序输出:
in enter
Traceback (most recent call last):
type: <type 'exceptions.ZeroDivisionError'>
val: integer division or modulo by zero
File "/home/user/cltdevelop/Code/TF_Practice_2017_06_06/with_test.py", line 36, in <module>
tb: <traceback object at 0x7f9e13fc6050>
sample.do_something()
File "/home/user/cltdevelop/Code/TF_Practice_2017_06_06/with_test.py", line 32, in do_something
bar = 1 / 0
ZeroDivisionError: integer division or modulo by zero
Process finished with exit code 1