|
|
|
|
移动端

3.4.2 模块 contextlib

《自学Python:编程基础、科学计算及数据分析》第3章Python 进阶,在本章中,我们将学习 Python的一些进阶用法,包括函数的进阶,迭代器、生成器、装饰器、上下文管理器的使用,以及 Python中的变量作用域。本节为大家介绍模块 contextlib。

作者:李金来源:机械工业出版社|2018-05-04 13:50

技术沙龙 | 邀您于8月25日与国美/AWS/转转三位专家共同探讨小程序电商实战

3.4.2 模块 contextlib

Python提供了contextlib模块来方便我们使用上下文管理器。

1.contextmanager装饰器

contextlib模块提供了装饰器contextmanager来实现一个简单的“上下文管理器”:

  1. In [1]: import contextlib  
  2. In [2]: @contextlib.contextmanager  
  3. ...: def test_manager():  
  4. ...: print "Entering"  
  5. ...: yield  
  6. ...: print "Exiting"  
  7. ...: 

contextmanager作为一个装饰器,对所修饰的函数有固定的要求:

该函数必须是一个生成器,且 yield只被执行一次。在该函数中,yield 之前的部分可以看成是.__enter__()方法的部分,yield返回的值可以看成是.__enter__()方法返回的值,yield之后的部分可以看成是.__exit__()方法的部分。

函数test_manager()返回了一个上下文管理器:

  1. In [3]: with test_manager():  
  2. ...: print "Hello world!"  
  3. ...:  
  4. Entering  
  5. Hello world!  
  6. Exiting 

使用yield的返回值:

  1. In [4]: @contextlib.contextmanager  
  2. ...: def test_manager():  
  3. ...: print "Entering"  
  4. ...: yield "Some value"  
  5. ...: print "Exiting"  
  6. ...:  
  7. In [5]: with test_manager() as value:  
  8. ...: print value  
  9. ...:  
  10. Entering  
  11. Some value  
  12. Exiting 

不过,这样定义出来的“上下文管理器”并不能在出错的时候保证后续处理被执行:

  1. In [6]: with test_manager():  
  2. ...: a = 1 / 0  
  3. ...:  
  4. Entering  
  5. -----------------------------------------------------------------------  
  6. ZeroDivisionError Traceback (most recent call last)  
  7. <ipython-input-6-56414ff38670> in <module>()  
  8. 1 with test_manager():  
  9. ----> 2 a = 1 / 0  
  10. ZeroDivisionError: integer division or modulo by zero 

使用 contextmanager构造的上下文管理器时,如果抛出异常,那么这个异常会在 yield的地方重新被抛出,我们可以使用try块的形式对yield的部分进行处理。此外,为了保证对应.__exit__()的部分始终被执行,我们需要将yield后面的部分放入finally块中:

  1. In [7]: @contextlib.contextmanager  
  2. ...: def test_manager():  
  3. ...: print "Entering"  
  4. ...: try:  
  5. ...: yield "Some value"  
  6. ...: except Exception as exc:  
  7. ...: print "Error:", exc  
  8. ...: finally:  
  9. ...: print "Exiting"  
  10. ...:  
  11. In [8]: with test_manager():  
  12. ...: a = 1 / 0  
  13. ...:  
  14. Entering  
  15. Error: integer division or modulo by zero  
  16. Exiting 

2.closing函数

contextlib模块中常用的还有 closing()函数。该函数接受一个对象,返回一个确保该对象的.close()方法被调用的上下文管理器,它相当于这样的一个函数:

  1. @contextmanager  
  2. def closing(thing):  
  3. try:  
  4. yield thing  
  5. finally:  
  6. thing.close() 

基本使用方法为:

  1. with closing(<object>):  
  2. <statesments> 

使用这种结构,我们能确保<object>的.close()方法最终被调用了,比如打开的网页:

  1. In [9]: import urllib  
  2. In [10]: from contextlib import closing  
  3. In [11]: with closing(urllib.urlopen('http://www.python.org')) as url:  
  4. ...: line = url.readline()  
  5. ...: print line  
  6. ...:  
  7. <!doctype html> 


喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

计算机病毒防范艺术

本书由Symantec首席反病毒研究员执笔,是讲述现代病毒威胁、防御技术和分析工具的权威指南。与多数讲述计算机病毒的书籍不同,本书完全是...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊