|
|
|
|
移动端

3.4.1 上下文管理器的原理(1)

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

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

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

3.4.1 上下文管理器的原理(1)

1. 基本形式和 with语句

with语句的基本用法如下:

  1. with <expression>:      
  2. <statements> 

其中<expression>是一个上下文管理器。

上下文管理器(Context Manager)是一个实现了.__enter__()方法和.__exit__()方法的对象。文件对象包含这两个方法,所以是一个合法的上下文管理器,可以用在with语句中:

  1. In [1]: f = open('tmp.txt', 'w')  
  2. In [2]: f.__enter__  
  3. Out[2]: <function __enter__> 
  4. In [3]: f.__exit__  
  5. Out[3]: <function __exit__> 
  6. In [4]: f.close() 

在 with语句中,上下文管理器的.__enter__()方法会在<statements>执行前执行,而.__exit__()方法会在<statements>执行结束后执行。任何实现了这两种方法的对象都是一个合法的上下文管理器。不过,上下文管理器的.__exit__()方法需要接受3个额外参数(加上self是四个)。

例如,我们定义这样一个上下文管理器:

  1. In [5]: class TestManager(object):  
  2. ...: def __enter__(self):  
  3. ...: print "Entering"  
  4. ...:  
  5. ...: def __exit__(self, exc_type, exc_value, traceback):  
  6. ...: print "Exiting"  
  7. ...: 

使用这个管理器:

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

如果<statements>在执行过程中抛出了异常,.__exit__()方法会先被执行,然后抛出异常:

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

2. 方法.__enter__()的返回值

为了在<statements>中使用文件对象,我们使用了 as关键字的形式,将 open()函数返回的文件对象赋给了 f。事实上,as关键字只是将上下文管理器.__enter__()方法的返回值赋给了f,而文件对象的.__enter__()方法的返回值刚好是它本身:

  1. In [8]: f = open('tmp.txt', 'w')  
  2. In [9]: f.__enter__() is f  
  3. Out[9]: True 

我们修改TestManager的定义,将.__enter__()的返回值修改为字符串"My value!":

  1. In [10]: class TestManager(object):  
  2. ...: def __enter__(self):  
  3. ...: print "Entering"  
  4. ...: return "My value!"  
  5. ...:  
  6. ...: def __exit__(self, exc_type, exc_value, traceback):  
  7. ...: print "Exiting"  
  8. ...: 

然后用 as关键字得到这个返回值:

  1. In [11]: with TestManager() as value:  
  2. ...: print value  
  3. ...:  
  4. Entering  
  5. My value!  
  6. Exiting 

返回这个上下文管理器本身是一种常用的设计:

  1. In [12]: class TestManager(object):  
  2. ...: def __enter__(self):  
  3. ...: print "Entering"  
  4. ...: return self  
  5. ...:  
  6. ...: def __exit__(self, exc_type, exc_value, traceback):  
  7. ...: print "Exiting"  
  8. ...:  
  9. In [13]: with TestManager() as value:  
  10. ...: print value  
  11. ...:  
  12. Entering  
  13. <__main__.ContextManager object at 0x0000000003D48828> 
  14. Exiting 

3. 方法.__exit__()与异常处理

在定义上下文管理器时,方法.__exit__()需要接受额外的参数,这些额外参数与异常处理相关。
重新定义TestManager,将这些参数打印出来:

  1. In [14]: class TestManager(object):  
  2. ...: def __enter__(self):  
  3. ...: print "Entering"  
  4. ...:  
  5. ...: def __exit__(self, exc_type, exc_value, traceback):  
  6. ...: print "Exiting"  
  7. ...: print "Arg:", exc_type  
  8. ...: print "Arg:", exc_value  
  9. ...: print "Arg:", traceback  
  10. ...: 

没有异常时:

  1. In [15]: with TestManager():  
  2. ...: a = 1 * 0  
  3. ...:  
  4. Entering  
  5. Exiting  
  6. Arg: None  
  7. Arg: None  
  8. Arg: None 


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

51CTO读书频道二维码


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

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

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

读 书 +更多

Fedora Core 5 Linux系统安装与管理

以Linux为代表的自由软件及其稳定性,逐渐在全世界崭露头角且备受重视。由于可以支持多种网络环境,因此在采用Linux系统之前,必须熟悉各种...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊