侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

详解Python中contextlib上下文管理模块的用法

Python  /  管理员 发布于 7年前   186

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

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

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

#encoding:utf-8class 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 @contextmanagerdef 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 contextmanagerfrom random import random DEFAULT_EXPIRES = 15DEFAULT_RETRIES = 5 @contextmanagerdef 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_errorwith Context(True):  raise RuntimeError('error message handled')printwith 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 [email protected] 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  printprint 'handled ereor:'with make_context() as value:  raise RuntimeError('show example of handling an error')printprint 'unhandled error:'with make_context() as value:  raise ValueError('this exception is not handled')

打印结果

Normal: entering inside with statement: {}  exitinghandled ereor:entering Error: show example of handling an error exitingunhandled error:enteringexitingTraceback (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 [email protected] make_context(name):  print 'entering:', name  yield name  print 'exiting:', namewith contextlib.nested(make_context('A'), make_context('B'), make_context('C')) as (A, B,   C):  print 'inside with statement:', A, B, C

打印结果

entering: Aentering: Bentering: Cinside with statement: A B Cexiting: Cexiting: Bexiting: A

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

import [email protected] make_context(name):  print 'entering:', name  yield name  print 'exiting:', namewith 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 contextlibclass 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使用get_text()方法从大段html中提取文本的实例
  • Python-Tkinter Text输入内容在界面显示的实例
  • 使用python读取.text文件特定行的数据方法
  • 对python opencv 添加文字 cv2.putText 的各参数介绍
  • Python tkinter的grid布局及Text动态显示方法
  • 对python Tkinter Text的用法详解
  • sublime text 3配置使用python操作方法
  • python编程开发之textwrap文本样式处理技巧
  • python可视化text()函数使用详解


  • 上一条:
    深入解析Python中的上下文管理器
    下一条:
    实例讲解Python中SocketServer模块处理网络请求的用法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客