简介
上下文管理属于流程控制特性中一部分,在python中,上下文管理语法主要是使用with关键词。with语句会设置一个临时的上下文,对对象进行控制,并且清除上下文,这样做的好处是能够减少错误,使得代码整洁易读。我们详细分析下流程控制的else,和上下文管理。
else字句
当然,else是我们经常用的关键词,相信大家大部分都是使用于if-else对。其实在python中,还有其他情况能使用else字句,当然都属于流程控制的范涛。如for/else、while/else 和 try/else。
- for/else对中else,当且仅当for循环运行完毕时,也就是所有元素都遍历,不能中断,else才会执行
for i in range(10):
pass
else:
print("---else----")
输出结果:
---else----
当for循环中有break时,else字句不会执行:
for i in range(10):
if i == 7:
break
else:
print("---else----")
- while/else句子中,当while循环因条件不满足而退出循环时,也就是没有break中断,else会被执行:
flag = 5
while flag:
flag -= 1
else:
print("---else----")
输出结果:
---else----
- try/else,当try语句没有抛出异常时,会执行else字句。
其实else在上述语句中不是很常用,但是也是有些情况使用会很方便的,例如:
for i in range(10):
if i == 12:
break
else:
print("列表中没有12")
上述情况下,使用else之后,无需设置控制标志或者额外的if语句,如果不使用else。恐怕要像下面这种写法了:
flag = 0
for i in range(10):
if i == 12:
flag = 1
break
if flag:
pass
else:
print("列表中没有12")
可见,有些时候在for循环使用else,也能省去很多麻烦的。
with语句
上下文管理器对象存在的目的是管理with语句,with语句的目的是简化try/finally 模式。用于保证一段代码执行后进行某些操作,即使抛出异常也会执行收尾工作。
上下文管理器主要包含两个特殊方法,__enter__
和__exit__
,with开始时,会调用上下文管理器对象的__enter__
方法,with结束后,会调用__exit__
方法。
最常见的with语句是文件打开,确保最后文件能够关闭:
with open("test.txt") as f:
pass
f绑定到打开的文件上面,是调用上下文管理器对象的__enter__
方法的结果。无论这个流程语句以何种情况结束,最后都会调用__exit__
方法。
如下,定义一个简单的上下文管理器对象:
class Test(object):
def __enter__(self):
print("enter")
def __exit__(self, exc_type, exc_value, traceback):
print("exit")
print(exc_type, exc_value, traceback)
with Test():
pass
输出结果:
enter
exit
None None None
若有异常:
class Test(object):
def __enter__(self):
print("enter")
def __exit__(self, exc_type, exc_value, traceback):
print("exit",exc_type, exc_value, traceback,"exit")
with Test():
a
输出结果:
enter
exit <class 'NameError'> name 'a' is not defined <traceback object at 0x000001A421F68708> exit
Traceback (most recent call last):
File "c:/Users/DELL/Desktop/ssj/search/descrip.py", line 12, in <module>
a
NameError: name 'a' is not defined
调用方法__enter__
时,除了self,不会传其他参数的。
调用__exit__
方法时:
没有异常发生时,除了self,传的三个参数都是None;
有异常情况时,三个参数的意义:
exc_type:异常类
exc_value:异常消息
traceback:traceback对象。
上下文管理器标准库中也有很多用法:
比如django数据库中的事务:
with transaction.atomic():
pass
threading 多线程中的锁:
whit threading.Lock():
pass
其实关于上下文管理器,有一个专门的内置库contextlib
这个模块提供了一个很实用的工具@contextmanager,这个装饰器能把生成器函数变成上下文管理器,
from contextlib import contextmanager
@contextmanager
def test():
print("enter")
yield "aaaa"
print("exit")
with test() as f:
pass
print(f)
输出结果:
enter
exit
aaaa
在使用@contextmanager装饰的生成器中,yield语句把上下分成两个部分,yield以上,是在with执行时,也就是调用方法__enter__
时,yield下面的代码在调用__exit__
方法时执行。