Describes the usage of the contextlib context management module in Python,

Source: Internet
Author: User
Tags print print

Describes the usage of the contextlib context management module in Python,

The OS module we use actually contains _ enter _ exit _ when reading files __. One is triggered by with, and the other is exited.

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

Then we can implement a standard with class. When I write python, I like to construct the with mode for some code that requires closing logic.

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

Contextlib is something more elegant than with and also a module that provides context mechanisms. It is implemented through the Generator modifier and is no longer implemented using _ enter _ and _ exit __. Contextmanager in contextlib provides a function-level context management mechanism.

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

I will post the usage of contextlib in the redis distributed lock code I wrote last time. In fact, at first glance, it is troublesome to use with and contextlib, but at least it makes your subject code clearer.

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

A context manager is activated through the with statement, and the API contains two methods. The _ enter _ () method runs the execution stream and enters the with code block. It returns the context of an object. When the execution stream leaves the with block, the context manager of the __exit _ () method clears any resources used.

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

Print results

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

When the context manager is executed, _ enter _ call _ exit _ when leaving will be called __.

_ Enter _ can return any object, and join a specified name with declaration.

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

Print results

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

If the context manager can handle exceptions, __exit _ () should return a value of True indicating that the exception does not need to be propagated. If False is returned, the exception will be caused after _ exit _ is executed.

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

Print results

__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


From generator to context Manager

It is not difficult to create a traditional method of context management by writing a class and the _ enter _ () and _ exit _ () methods. But sometimes the overhead you need is only a negligible context for management. In this case, you can use the contextmanager () decorat or generator function to convert a context manager.

import contextlib@contextlib.contextmanagerdef 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')

Print results

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 Context

You can use nested () to manage multiple contexts at the same time.

import contextlib@contextlib.contextmanagerdef 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

Print results

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

Because Python 2.7 and later versions do not support the use of nested (), because it can be directly nested

import contextlib@contextlib.contextmanagerdef 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


Close open Handle

The file class supports the context manager, but some objects are not supported. Some Classes use the close () method but do not support the context manager. We use closing () to create a context manager for him. (The class must have the close method)

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

Print results

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

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.