上下文管理属于流程控制特性中一部分,在python中,上下文管理语法主要是使用with关键词。with语句会设置一个临时的上下文,对对象进行控制,并且清除上下文
with context_expression [as target(s)]:
...
with-body
...
其中 context_expression 可以是任意表达式;as target(s) 是可选的
with…as 是 python 的控制流语句,像 if ,while一样。with…as 语句是简化版的 try except finally语句。
先理解一下 try…except…finally 语句是干啥的。实际上 try…except 语句和 try…finally 语句是两种语句,用于不同的场景。但是当二者结合在一起时,可以“实现稳定性和灵活性更好的设计”。
完整的try…finallly 语句实现:
try:
execution block ##正常执行模块
except A:
exc A block ##发生A错误时执行
except B:
exc B block ##发生B错误时执行
except:
other block ##发生除了A,B错误以外的其他错误时执行
else:
if no exception, jump to here ##没有错误时执行
finally:
final block ##总是执行
tips: 注意顺序不能乱,否则会有语法错误。如果用 else 就必须有 except,否则会有语法错误。
try:
a = 1 / 2
print(a)
print(m) # 抛出 NameError异常, 此后的语句都不在执行
b = 1 / 0
print(b)
c = 2 / 1
print(c)
except NameError:
print("Ops!!") # 捕获到异常
except ZeroDivisionError:
print("Wrong math!!")
except:
print("Error")
else:
print("No error! yeah!")
finally: # 是否异常都执行该代码块
with 语句执行过程 。在语义上等价于:
context_manager = context_expression
exit = type(context_manager).__exit__
value = type(context_manager).__enter__(context_manager)
exc = True # True 表示正常执行,即便有异常也忽略;False 表示重新抛出异常,需要对异常进行处理
try:
try:
target = value # 如果使用了 as 子句
with-body # 执行 with-body
except:
# 执行过程中有异常发生
exc = False
# 如果 __exit__ 返回 True,则异常被忽略;如果返回 False,则重新抛出异常
# 由外层代码对异常进行处理
if not exit(context_manager, *sys.exc_info()):
raise
finally:
# 正常退出,或者通过 statement-body 中的 break/continue/return 语句退出
# 或者忽略异常退出
if exc:
exit(context_manager, None, None, None)
程序有错的例子:
class Sample:
def __enter__(self):
return self
def __exit__(self, type, value, trace):
print("type:", type)
print("value:", value)
print("trace:", trace)
def do_something(self):
bar = 1 / 0
return bar + 10
with Sample() as sample:
sample.do_something()
步骤分析:
–> 实例化Sample类,执行类方法__enter__(),返回值self也就是实例自己赋值给sample。即sample是Sample的一个实例(对象);
–>执行with-block码块: 实例sample调用方法do_something();
–>执行do_something()第一行 bar = 1 / 0,发现ZeroDivisionError,直接结束with-block代码块运行
–>执行类方法__exit__(),带入ZeroDivisionError的错误信息值,也就是type,value, trace,并打印它们。