手机
当前位置:查字典教程网 >脚本专栏 >python >详解Python中contextlib上下文管理模块的用法
详解Python中contextlib上下文管理模块的用法
摘要:咱们用的os模块,读取文件的时候,其实他是含有__enter____exit__。一个是with触发的时候,一个是退出的时候。withfil...

咱们用的os模块,读取文件的时候,其实他是含有__enter__ __exit__ 。 一个是with触发的时候,一个是退出的时候。

with file('nima,'r') as f: print f.readline()

那咱们自己再实现一个标准的可以with的类。 我个人写python的时候,喜欢针对一些需要有关闭逻辑的代码,构造成with的模式 。

#encoding:utf-8 class echo: def __enter__(self): print 'enter' def __exit__(self,*args): print 'exit' with echo() as e: print 'nima'

contextlib是个比with优美的东西,也是提供上下文机制的模块,它是通过Generator装饰器实现的,不再是采用__enter__和__exit__。contextlib中的contextmanager作为装饰器来提供一种针对函数级别的上下文管理机制。

from contextlib import contextmanager @contextmanager def make_context() : print 'enter' try : yield {} except RuntimeError, err : print 'error' , err finally : print 'exit' with make_context() as value : print value

我这里再贴下我上次写的redis分布式锁代码中有关于contextlib的用法。其实乍一看,用了with和contextlib麻烦了,但是最少让你的主体代码更加鲜明了。

from contextlib import contextmanager from random import random DEFAULT_EXPIRES = 15 DEFAULT_RETRIES = 5 @contextmanager def dist_lock(key, client): key = 'lock_%s' % key try: _acquire_lock(key, client) yield finally: _release_lock(key, client) def _acquire_lock(key, client): for i in xrange(0, DEFAULT_RETRIES): get_stored = client.get(key) if get_stored: sleep_time = (((i+1)*random()) + 2**i) / 2.5 print 'Sleeipng for %s' % (sleep_time) time.sleep(sleep_time) else: stored = client.set(key, 1) client.expire(key,DEFAULT_EXPIRES) return raise Exception('Could not acquire lock for %s' % key) def _release_lock(key, client): client.delete(key)

Context Manager API

一个上下文管理器通过with声明激活, 而且API包含两个方法。__enter__()方法运行执行流进入到with代码块内。他返回一个对象共上下文使用。当执行流离开with块时,__exit__()方法上下文管理器清除任何资源被使用。

class Context(object): def __init__(self): print '__init__()' def __enter__(self): print '__enter__()' return self def __exit__(self, exc_type, exc_val, exc_tb): print '__exit__()' with Context(): print 'Doing work in the context.'

打印结果

__init__() __enter__() Doing work in the context. __exit__()

执行上下文管理器时会调用__enter__离开时调用__exit__。

__enter__能返回任意对象,联合一个指定名字于with声明。

class WithinContext(object): def __init__(self, context): print 'WithinContext.__init__(%s)' % context def do_something(self): print 'WithinContext.do_something()' def __del__(self): print 'WithinContext.__del__' class Context(object): def __init__(self): print '__init__()' def __enter__(self): print '__enter__()' return WithinContext(self) def __exit__(self, exc_type, exc_val, exc_tb): print '__exit__()' with Context() as c: c.do_something()

打印结果

__init__() __enter__() WithinContext.__init__(<__main__.Context object at 0x7f579d8e4890>) WithinContext.do_something() __exit__() WithinContext.__del__

如果上下文管理器能处理异常,__exit__()应该返回一个True值表明这个异常不需要传播,返回False异常会在执行__exit__之后被引起。

class Context(object): def __init__(self, handle_error): print '__init__(%s)' % handle_error self.handle_error = handle_error def __enter__(self): print '__enter__()' return self def __exit__(self, exc_type, exc_val, exc_tb): print '__exit__(%s, %s, %s)' % (exc_type, exc_val, exc_tb) return self.handle_error with Context(True): raise RuntimeError('error message handled') print with Context(False): raise RuntimeError('error message propagated')

打印结果

__init__(True) __enter__() __exit__(<type 'exceptions.RuntimeError'>, error message handled, <traceback object at 0x7fdfb32f8b00>) __init__(False) __enter__() __exit__(<type 'exceptions.RuntimeError'>, error message propagated, <traceback object at 0x7fdfb32f8b90>) Traceback (most recent call last): File "test.py", line 23, in <module> raise RuntimeError('error message propagated') RuntimeError: error message propagated

从生成器到上下文管理器

创建上下文管理的传统方法,通过编写一个类与__enter__()和__exit__()方法,并不困难。但有时比你需要的开销只是管理一个微不足道的上下文。在这类情况下,您可以使用contextmanager() decorat or 生成器函数转换成一个上下文管理器。

import contextlib @contextlib.contextmanager def make_context(): print ' entering' try: yield {} except RuntimeError, err: print ' Error:', err finally: print ' exiting' print 'Normal:' with make_context() as value: print ' inside with statement:', value print print 'handled ereor:' with make_context() as value: raise RuntimeError('show example of handling an error') print print 'unhandled error:' with make_context() as value: raise ValueError('this exception is not handled')

打印结果

Normal: entering inside with statement: {} exiting handled ereor: entering Error: show example of handling an error exiting unhandled error: entering exiting Traceback (most recent call last): File "test.py", line 30, in <module> raise ValueError('this exception is not handled') ValueError: this exception is not handled

嵌套上下文

使用nested()可以同时管理多个上下文。

import contextlib @contextlib.contextmanager def make_context(name): print 'entering:', name yield name print 'exiting:', name with contextlib.nested(make_context('A'), make_context('B'), make_context('C')) as (A, B, C): print 'inside with statement:', A, B, C

打印结果

entering: A entering: B entering: C inside with statement: A B C exiting: C exiting: B exiting: A

因为Python 2.7和以后的版本不赞成使用nested(),因为可以直接嵌套

import contextlib @contextlib.contextmanager def make_context(name): print 'entering:', name yield name print 'exiting:', name with make_context('A') as A, make_context('B') as B, make_context('C') as C: print 'inside with statement:', A, B, C

关闭open的句柄

文件类支持上下文管理器, 但是有一些对象不支持。还有一些类使用close()方法但是不支持上下文管理器。我们使用closing()来为他创建一个上下文管理器。(类必须有close方法)

import contextlib class Door(object): def __init__(self): print ' __init__()' def close(self): print ' close()' print 'Normal Example:' with contextlib.closing(Door()) as door: print ' inside with statement' print print 'Error handling example:' try: with contextlib.closing(Door()) as door: print ' raising from inside with statement' raise RuntimeError('error message') except Exception, err: print ' Had an error:', err

打印结果

Normal Example: __init__() inside with statement close() Error handling example: __init__() raising from inside with statement close() Had an error: error message

【详解Python中contextlib上下文管理模块的用法】相关文章:

Python实现的几个常用排序算法实例

讲解python参数和作用域的使用

使用Python获取Linux系统的各种信息

python中文乱码的解决方法

python逐行读取文件内容的三种方法

Python 开发Activex组件方法

Python中使用动态变量名的方法

python生成器的使用方法

Python中apply函数的用法实例教程

python中stdout输出不缓存的设置方法

精品推荐
分类导航