Python中的上下文管理

2,564次阅读
没有评论

共计 2369 个字符,预计需要花费 6 分钟才能阅读完成。

## **上下文管理器(Context Manager)**

上下文管理器是指在一段代码执行之前执行一段代码,用于一些预处理工作;执行之后再执行一段代码,用于一些清理工作。比如打开文件进行读写,读写完之后需要将文件关闭。又比如在数据库操作中,操作之前需要连接数据库,操作之后需要关闭数据库。在上下文管理协议中,有两个方法__enter__和__exit__,分别实现上述两个功能。

## **with语法**

讲到上下文管理器,就不得不说到python的with语法。基本语法格式为:

with EXPR as VAR:
    BLOCK

这里就是一个标准的上下文管理器的使用逻辑,稍微解释一下其中的运行逻辑:

(1)执行EXPR语句,获取上下文管理器(Context Manager)

(2)调用上下文管理器中的__enter__方法,该方法执行一些预处理工作。

(3)这里的as VAR可以省略,如果不省略,则将__enter__方法的返回值赋值给VAR。

(4)执行代码块BLOCK,这里的VAR可以当做普通变量使用。

(5)最后调用上下文管理器中的的__exit__方法。

(6)__exit__方法有三个参数:exc_type, exc_val, exc_tb。如果代码块BLOCK发生异常并退出,那么分别对应异常的type、value 和 traceback。否则三个参数全为None。

(7)__exit__方法的返回值可以为True或者False。如果为True,那么表示异常被忽视,相当于进行了try-except操作;如果为False,则该异常会被重新raise。

## **实例:自己实现打开文件操作**

class LookingGlass:
    def __enter__(self):
        import sys
        self.original_write = sys.stdout.write
        sys.stdout.write = self.reverse_write
        return 'JABBERWOCKY'
    def reverse_write(self, text):
        self.original_write(text[::-1])
    def __exit__(self, exc_type, exc_value, traceback):
        import sys
        sys.stdout.write = self.original_write
        if exc_type is ZeroDivisionError:
            print('Please DO NOT divide by zero!')
            return True

代码很简单,也很容易理解,这里不做过多解释。

## **内置库contextlib的使用**

closing
提供关闭的方法,比如创建的文件打开关闭或者http连接关闭
suppress

提供上下文管理忽略制定的异常
@contextmanager
装饰器用于快速生成上下文管理器
ContextDecorator
基类用于上下文管理器
ExitStack

上下文管理器,使您可以输入可变数量的上下文管理器。 什么时候
with块结束时,ExitStack调用堆叠的上下文管理器的退出
方法按LIFO顺序(最后输入,先退出)。 不使用时使用此课程
事先知道您需要输入多少个上下文管理器
块; 例如,当同时打开任意文件列表中的所有文件时
时间。

但是最常用的还是 contextmanager

(1)装饰器contextmanager。该装饰器将一个函数中yield语句之前的代码当做__enter__方法执行,yield语句之后的代码当做__exit__方法执行。同时yield返回值赋值给as后的变量。

import contextlib
@contextlib.contextmanager
def looking_glass():
		import sys
		original_write = sys.stdout.write
		def reverse_write(text):
			original_write(text[::-1])
		sys.stdout.write = reverse_write
		msg = ''
		try:
			yield 'JABBERWOCKY'
		except ZeroDivisionError:
			msg = 'Please DO NOT divide by zero!'
		finally:
			sys.stdout.write = original_write
			if msg:
				print(msg)
In [1]: import contextlib 
        @contextlib.contextmanager 
        def looking_glass(): 
             import sys 
             original_write = sys.stdout.write 
             def reverse_write(text): 
                 original_write(text[::-1]) 
             sys.stdout.write = reverse_write 
             msg = '' 
             try: 
                 yield 'JABBERWOCKY' 
             except ZeroDivisionError: 
                 msg = 'Please DO NOT divide by zero!' 
             finally: 
                 sys.stdout.write = original_write 
                 if msg: 
                     print(msg)                                                                                                                     

In [2]: a=looking_glass()                                                                                                    

In [3]: b=a.__enter__()                                                                                                      

In [4]: b                                                                                                                    
Out[4]: 'YKCOWREBBAJ'

In [5]: a.__exit__()                                                                                                         
'kcabecart' dna ,'eulav' ,'epyt' :stnemugra lanoitisop deriuqer 3 gnissim )(__tixe__ :m0[orrEepyTm13;0[
0[
0[0[43;0[0[43;0[0[43;0[0[43;0[0[0[43;0[0[m0[13;0[ >----m23;0[
0[43;0[eludom
正文完
请博主喝杯咖啡吧!
post-qrcode
 
admin
版权声明:本站原创文章,由 admin 2021-01-18发表,共计2369字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码