导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及我的心得,打算入门Python的朋友们能够来一块儿学习并交流。
本文重点:python
一、掌握if语句以外的else的用法;
二、掌握上下文管理器的定义、协议、使用和with块;
三、掌握有用的@contextmanger装饰器。
if/else中if和else是同级对立的语句,对立是指流程通过一层if/else语句只能对应一种处理语句。而else在for/else,while/else,try/else语句中的功能则大相径庭。后者中的else功能以下:数据库
for循环没有被break语句停止才运行else块。
while循环没有被break语句停止才运行else块。
try块中,没有异常抛出时才运行else块。
下面以for/else为例进行代码实现:编程
for i in "apple": if i.isupper(): break else: raise ValueError('No upper string was found')
try/except不只用于处理错误,还用于处理错误,这属于EAFP编程风格。app
即先假定存在有效的键或属性,若是假定不成立,那么捕获异常。
即在调用函数或查找属性或键以前显式测试前提条件。
上下文管理器(context manger):在操做文件和创建数据库链接的时候,咱们最终须要关闭资源,这就是上下文管理器存在的意义。上下文管理器协议:包含__enter__和__exit__两个方法。
语法:try/finally模式和with语句
实例:try/finally模式函数
try: f = open('test.txt', 'a+') f.write('Foo\n') finally: f.close()
接下来咱们用with语句进行替换:
实例:with语句工具
with open('test.txt', 'a+') as f: f.write('Foo\n')
分析:open 的返回值赋值给变量 f,当离开 with 代码块的时候,系统会自动调用 f.close() 方法。总结:with块的功能在于简化try/finally模式。with语句在开始运行时会在上下文管理器对象上调用__enter__,而with语句结束时会调用__exit__方法。
Tips:with语句中的as语句是可选的,as语句将__enter__返回的值绑定到as语句后的变量。值得注意的是,对于open函数必须加上as字句来获取文件的引用。学习
在掌握基本上下文管理器和with语句后,咱们经过自定义上下文管理器来深入认识with语句和__enter__以及__exit__的联系。
实例:自定义知足上下文管理器协议的类测试
class OpenFileDemo(object): def __init__(self, filename): self.filename = filename self.f = open(self.filename, 'a+') return self.f def __exit__(self, exc_type, exc_value, traceback): self.f.close() if exc_type != SyntaxError: return True return False with OpenFileDemo('test.txt') as f: f.write('Foo\n')
当上下文管理器遇到异常时由__exit__方法处理。传给__exit__方法的三个参数以下:
exc_type:异常类(例如SyntaxError)。
exc_value:异常实例。有时会有参数传给异常构造方法,例如错误信息,可使用exc_value.args获取这些参数。
traceback:traceback对象。code
@contextmanger装饰器是contextlib模块中的工具,它能够将包含yield的语句变成上下文管理器。
其中,yield以前的语句在__enter__方法中执行
,yield以后的语句在__exit__方法执行
,yield后面的值是函数的返回值,绑定到实际调用的with中的as子句的目标变量上
。
如此能够避免编写一个类来实现上下文管理器协议。对象
实例:@contextmanger装饰器应用之计时器
import contextlib import time @contextlib.contextmanager def timer(): start=time.time() yield end=time.time() usedtime=end-start print('Running time was %r seconds'%usedtime) with timer() as usedtime: time.sleep(1)
注意:一旦with块在调用timer出现异常时,抛出的异常会在timer函数中的yield表达式中再次抛出。若是timer函数没有处理异常的代码就会致使函数运行停止,系统处于无效状态。所以必要时在上下文管理器函数中使用try/finally语句防范错误。
@contextmanger集合了三个不一样的Python特性:函数装饰器、生成器和with语句,很是实用!
最后说明contextlib模块中包含的实用工具:
closing
: 若是对象提供了 close() 方法,但没有实现 _enter__/__exit_ 协议,那么可使用这个函数构建上下文管理器。suppress
: 构建临时忽略指定异常的上下文管理器。@contextmanager
: 这个装饰器把简单的生成器函数变成上下文管理器,这样就不用建立类去实现管理器协议了。ContextDecorator
: 这是个基类,用于定义基于类的上下文管理器。这种上下文管理器也能用于装饰函数,在受管理的上下文中运行整个函数。ExitStack
: 这个上下文管理器能进入多个上下文管理器。with 块结束时,ExitStack 按照后进先出的顺序调用栈中各个上下文管理器的_exit_ 方法。若是事先不知道 with 块要进入多少个上下文管理器,可使用这个类。例如,同时打开任意一个文件列表中的全部文件。显然,在这些实用工具中,使用最普遍的是 @contextmanager 装饰器,所以要格外留心。这个装饰器也有迷惑人的一面,由于它与迭代无关,却要使用 yield 语句。