首页 > 编程 > Python > 正文

深入学习Python中的上下文管理器与else块

2020-01-04 16:49:32
字体:
来源:转载
供稿:网友

前言

本文主要个大家介绍了关于Pythonpython/84646.html">python/205749.html">上下文管理器与else块的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

在开始之前,我们先来看看下面这段话:

最终,上下文管理器可能几乎与子程序(subroutine)本身一样重要。目前,我们只了解了上下文管理器的皮毛……Basic 语言有with 语句,而且很多语言都有。但是,在各种语言中 with 语句的作用不同,而且做的都是简单的事,虽然可以避免不断使用点号查找属性,但是不会做事前准备和事后清理。不要觉得名字一样,就意味着作用也一样。with 语句是非常了不起的特性。

——Raymond Hettinger

雄辩的 Python 布道者

先做这个,再做那个:if语句之外的else块

这个语言特性不是什么秘密,但却没有得到重视:else 子句不仅能在if 语句中使用,还能在 for、while 和 try 语句中使用。for/else、while/else 和 try/else 的语义关系紧密,不过与if/else 差别很大。起初,else 这个单词的意思阻碍了我对这些特性的理解,但是最终我习惯了。

else 子句的行为如下:

for

  仅当 for 循环运行完毕时(即 for 循环没有被 break 语句中止)才运行 else 块。

while

  仅当 while 循环因为条件为假值而退出时(即 while 循环没有被break 语句中止)才运行 else 块。

try

  仅当 try 块中没有异常抛出时才运行 else 块。官方文档(https://docs.python.org/3/reference/compound_stmts.html)还指出:“else 子句抛出的异常不会由前面的 except 子句处理。”

注意:

  在所有情况下,如果异常或者 return、break 或 continue 语句导致控制权跳到了复合语句的主块之外,else 子句也会被跳过。

  在这些语句中使用 else 子句通常能让代码更易于阅读,而且能省去一些麻烦,不用设置控制标志或者添加额外的 if 语句。

在循环中使用 else 子句的方式如下述代码片段所示:

 for item in my_list:  if item.flavor == 'banana':   break  else:   raise ValueError('No banana flavor found!')

一开始,你可能觉得没必要在 try/except 块中使用 else 子句。毕竟,在下述代码片段中,只有 dangerous_call() 不抛出异常,after_call() 才会执行,对吧?

 try:  dangerous_call()  after_call() except OSError:  log('OSError...')

然而,after_call() 不应该放在 try 块中。为了清晰和准确,try 块中应该只抛出预期异常的语句。因此,像下面这样写更好:

 try:  dangerous_call() except OSError:  log('OSError...') else:  after_call()

现在很明确,try 块防守的是 dangerous_call() 可能出现的错误,而不是 after_call() 。而且很明显,只有 try 块不抛出异常,才会执行after_call()

上下文管理器和with块

  上下文管理器对象存在的目的是管理 with 语句,就像迭代器的存在是为了管理 for 语句一样。

  with 语句的目的是简化 try/finally 模式。这种模式用于保证一段代码运行完毕后执行某项操作,即便那段代码由于异常、return 语句或sys.exit() 调用而中止,也会执行指定的操作。finally 子句中的代码通常用于释放重要的资源,或者还原临时变更的状态。

  上下文管理器协议包含 __enter__ 和 __exit__ 两个方法。with 语句开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with 语句运行结束后,会在上下文管理器对象上调用 __exit__ 方法,以此扮演 finally 子句的角色。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表