欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Python中contextlib上下文管理模塊的用法

 更新時(shí)間:2016年06月28日 15:36:09   作者:cangmean  
Python中一些內(nèi)建對(duì)象有了上下文管理器的支持,于是可以使用with語(yǔ)句來(lái)實(shí)現(xiàn)自動(dòng)的文件打開(kāi)關(guān)閉以及線程操作等,這里我們就從根基上來(lái)詳解Python中contextlib上下文管理模塊的用法

咱們用的os模塊,讀取文件的時(shí)候,其實(shí)他是含有__enter__ __exit__ 。  一個(gè)是with觸發(fā)的時(shí)候,一個(gè)是退出的時(shí)候。

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

那咱們自己再實(shí)現(xiàn)一個(gè)標(biāo)準(zhǔn)的可以with的類。 我個(gè)人寫(xiě)python的時(shí)候,喜歡針對(duì)一些需要有關(guān)閉邏輯的代碼,構(gòu)造成with的模式 。 

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

contextlib是個(gè)比with優(yōu)美的東西,也是提供上下文機(jī)制的模塊,它是通過(guò)Generator裝飾器實(shí)現(xiàn)的,不再是采用__enter__和__exit__。contextlib中的contextmanager作為裝飾器來(lái)提供一種針對(duì)函數(shù)級(jí)別的上下文管理機(jī)制。

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

我這里再貼下我上次寫(xiě)的redis分布式鎖代碼中有關(guān)于contextlib的用法。其實(shí)乍一看,用了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

一個(gè)上下文管理器通過(guò)with聲明激活, 而且API包含兩個(gè)方法。__enter__()方法運(yùn)行執(zhí)行流進(jìn)入到with代碼塊內(nèi)。他返回一個(gè)對(duì)象共上下文使用。當(dāng)執(zhí)行流離開(kāi)with塊時(shí),__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.'

打印結(jié)果

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

執(zhí)行上下文管理器時(shí)會(huì)調(diào)用__enter__離開(kāi)時(shí)調(diào)用__exit__。

__enter__能返回任意對(duì)象,聯(lián)合一個(gè)指定名字于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()

打印結(jié)果

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

如果上下文管理器能處理異常,__exit__()應(yīng)該返回一個(gè)True值表明這個(gè)異常不需要傳播,返回False異常會(huì)在執(zhí)行__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')

打印結(jié)果

__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


從生成器到上下文管理器

創(chuàng)建上下文管理的傳統(tǒng)方法,通過(guò)編寫(xiě)一個(gè)類與__enter__()和__exit__()方法,并不困難。但有時(shí)比你需要的開(kāi)銷只是管理一個(gè)微不足道的上下文。在這類情況下,您可以使用contextmanager() decorat or 生成器函數(shù)轉(zhuǎn)換成一個(gè)上下文管理器。

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')

打印結(jié)果

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()可以同時(shí)管理多個(gè)上下文。

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

打印結(jié)果

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

因?yàn)镻ython 2.7和以后的版本不贊成使用nested(),因?yàn)榭梢灾苯忧短?/p>

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


關(guān)閉open的句柄

文件類支持上下文管理器, 但是有一些對(duì)象不支持。還有一些類使用close()方法但是不支持上下文管理器。我們使用closing()來(lái)為他創(chuàng)建一個(gè)上下文管理器。(類必須有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

打印結(jié)果

Normal Example:
  __init__()
  inside with statement
  close()

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

相關(guān)文章

  • Python基于traceback模塊獲取異常信息

    Python基于traceback模塊獲取異常信息

    這篇文章主要介紹了Python基于traceback模塊獲取異常信息,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 深入理解Python中的super()方法

    深入理解Python中的super()方法

    super 是用來(lái)解決多重繼承問(wèn)題的,直接用類名調(diào)用父類方法在使用單繼承的時(shí)候沒(méi)問(wèn)題,但是如果使用多繼承,會(huì)涉及到查找順序(MRO)、重復(fù)調(diào)用(鉆石繼承)等種種問(wèn)題。這篇文章主要給大家介紹了關(guān)于Python中super()方法的相關(guān)資料,需要的朋友可以參考下。
    2017-11-11
  • python 通過(guò)類中一個(gè)方法獲取另一個(gè)方法變量的實(shí)例

    python 通過(guò)類中一個(gè)方法獲取另一個(gè)方法變量的實(shí)例

    今天小編就為大家分享一篇python 通過(guò)類中一個(gè)方法獲取另一個(gè)方法變量的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • Python2和Python3中urllib庫(kù)中urlencode的使用注意事項(xiàng)

    Python2和Python3中urllib庫(kù)中urlencode的使用注意事項(xiàng)

    這篇文章主要介紹了Python2和Python3中urllib庫(kù)中urlencode的使用注意事項(xiàng),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-11-11
  • Python詳解復(fù)雜CSV文件處理方法

    Python詳解復(fù)雜CSV文件處理方法

    這篇文章主要介紹了Python數(shù)據(jù)讀寫(xiě)之Python讀寫(xiě)CSV文件,CSV即逗號(hào)分隔值,一種以逗號(hào)分隔按行存儲(chǔ)的文本文件,所有的值都表現(xiàn)為字符串類型,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-07-07
  • 在PyCharm的 Terminal(終端)切換Python版本的方法

    在PyCharm的 Terminal(終端)切換Python版本的方法

    這篇文章主要介紹了在PyCharm的 Terminal(終端)切換Python版本的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Python出現(xiàn)segfault錯(cuò)誤解決方法

    Python出現(xiàn)segfault錯(cuò)誤解決方法

    這篇文章主要介紹了Python出現(xiàn)segfault錯(cuò)誤解決方法,分析了系統(tǒng)日志提示segfault錯(cuò)誤的原因與對(duì)應(yīng)的解決方法,需要的朋友可以參考下
    2016-04-04
  • python 梯度法求解函數(shù)極值的實(shí)例

    python 梯度法求解函數(shù)極值的實(shí)例

    今天小編就為大家分享一篇python 梯度法求解函數(shù)極值的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07
  • python3實(shí)現(xiàn)爬取淘寶美食代碼分享

    python3實(shí)現(xiàn)爬取淘寶美食代碼分享

    本文給大家分享的是如何使用python3來(lái)爬取淘寶美食圖片標(biāo)題等信息的方法和代碼,有需要的小伙伴可以參考下
    2018-09-09
  • python/Matplotlib繪制復(fù)變函數(shù)圖像教程

    python/Matplotlib繪制復(fù)變函數(shù)圖像教程

    今天小編就為大家分享一篇python/Matplotlib繪制復(fù)變函數(shù)圖像教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11

最新評(píng)論