Python实现上下文管理器的方法
问题
你想自己去实现一个新的上下文管理器,以便使用with语句。
解决方案
实现一个新的上下文管理器的最简单的方法就是使用contexlib模块中的@contextmanager装饰器。下面是一个实现了代码块计时功能的上下文管理器例子:
importtime fromcontextlibimportcontextmanager @contextmanager deftimethis(label): start=time.time() try: yield finally: end=time.time() print('{}:{}'.format(label,end-start)) #Exampleuse withtimethis('counting'): n=10000000 whilen>0: n-=1
在函数timethis()中,yield之前的代码会在上下文管理器中作为__enter__()方法执行,所有在yield之后的代码会作为__exit__()方法执行。如果出现了异常,异常会在yield语句那里抛出。
下面是一个更加高级一点的上下文管理器,实现了列表对象上的某种事务:
@contextmanager deflist_transaction(orig_list): working=list(orig_list) yieldworking orig_list[:]=working
这段代码的作用是任何对列表的修改只有当所有代码运行完成并且不出现异常的情况下才会生效。下面我们来演示一下:
>>>items=[1,2,3] >>>withlist_transaction(items)asworking: ...working.append(4) ...working.append(5) ... >>>items [1,2,3,4,5] >>>withlist_transaction(items)asworking: ...working.append(6) ...working.append(7) ...raiseRuntimeError('oops') ... Traceback(mostrecentcalllast): File"",line4,in RuntimeError:oops >>>items [1,2,3,4,5] >>>
讨论
通常情况下,如果要写一个上下文管理器,你需要定义一个类,里面包含一个__enter__()和一个__exit__()方法,如下所示:
importtime classtimethis: def__init__(self,label): self.label=label def__enter__(self): self.start=time.time() def__exit__(self,exc_ty,exc_val,exc_tb): end=time.time() print('{}:{}'.format(self.label,end-self.start))
尽管这个也不难写,但是相比较写一个简单的使用@contextmanager注解的函数而言还是稍显乏味。
@contextmanager应该仅仅用来写自包含的上下文管理函数。如果你有一些对象(比如一个文件、网络连接或锁),需要支持with语句,那么你就需要单独实现__enter__()方法和__exit__()方法。
以上就是Python实现上下文管理器的方法的详细内容,更多关于Python实现上下文管理器的资料请关注毛票票其它相关文章!