Contextlib-context manager tool
2012-07-27 magnet
# Undertake software automation implementation and training and other gtalk: ouyangchongwu # gmail.com qq 37391319 blog: testing.blog.chinaunix.net
# Copyright. For reposted content, please contact us by letter
# Automated testing and python group: http://groups.google.com/group/automation_testing_python
# Reference: ThePython Standard Library by Example
# Experiment environment: Python2.7.3 CentOS release 6.2 (Final) 32 bits
3.4 contextlib-context manager tool
Purpose: Create and process the context manager tool.
Python version: 2.5 or later
The contextlib module contains tools used to process the context manager and with statements. The context manager and with statement can reduce the number of try: finally blocks and the required indentation level.
Note: The context manager must be associated with the with statement. Since it is officially considered that with is a part of Python 2.6, We need to import it from _ ure _ before using contextlib in Python2.5. For example, from _ future _ import with_statement.
3.4.1 context manager API
The context manager is responsible for resources in a code block. It may create resources when you enter the code block, and then clear the resources when you exit the code block. For example, files support the context manager API, which can easily disable files after reading and writing files.
With open ('/tmp/pymotw.txt', 'wt ') as f:
F. write ('tents go here ')
# File isautomatically closed
The context manager is enabled by the with statement. This API contains two methods. When the execution flow enters the with code block, the _ enter _ () method is run. It returns an object, which is used in this context. When the execution stream leaves the with block, the context manager's _ exit _ () method is called to clear the resources used.
#! /Usr/bin/envpython
# Encoding: UTF-8
#
# Copyright (c) 2010 Doug Hellmann. All rightsreserved.
#
"Implementingthe context manager API by hand.
"""
# End_pymotw_header
ClassContext (object ):
Def _ init _ (self ):
Print '_ init __()'
Def _ enter _ (self ):
Print '_ enter __()'
Return self
Def _ exit _ (self, exc_type, exc_val, exc_tb ):
Print '_ exit __()'
WithContext ():
Print 'doing work in the context'
The combination of the context manager and the with statement is a more compact method of try: finally block, because the _ exit _ () method of the context manager will always be called, this is true even when exceptions occur. The execution result is as follows:
# Python contextlib_api.py
_ Init __()
_ Enter __()
Doing work inthe context
_ Exit __()
If a name is specified in the as clause of the with statement, the __enter _ () method can return any object associated with this name. In this example, Context returns an object that uses the Context.
#! /Usr/bin/env python
# Encoding: UTF-8
#
# Copyright (c) 2010 Doug Hellmann. All rightsreserved.
#
"Implementingthe context manager API by hand.
"""
# End_pymotw_header
ClassWithinContext (object ):
Def _ init _ (self, context ):
Print 'withincontext. _ init _ (% s) '% context
Def do_something (self ):
Print 'withincontext. do_something ()'
Def _ del _ (self ):
Print 'withincontext. _ del __'
ClassContext (object ):
Def _ init _ (self ):
Print 'Context. _ init __()'
Def _ enter _ (self ):
Print 'Context. _ enter __()'
Return WithinContext (self)
Def _ exit _ (self, exc_type, exc_val, exc_tb ):
Print 'Context. _ exit __()'
WithContext () as c:
C. do_something ()
Execution result:
Pythoncontextlib_api_other_object.py
Context. _ init __()
Context. _ enter __()
WithinContext. _ init _ (<__ main _. Contextobject at 0xb77684cc>)
WithinContext. do_something ()
Context. _ exit __()
WithinContext. _ del __
The _ exit _ () method receives some parameters, including detailed information about exceptions generated in the with block.
#! /Usr/bin/env python
# Encoding: UTF-8
#
# Copyright (c) 2010 Doug Hellmann. All rightsreserved.
#
"Implementingthe context manager API by hand.
"""
# End_pymotw_header
ClassContext (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 __()'
Print 'exc_type = ', exc_type
Print 'exc_val = ', exc_val
Print 'exc_tb = ', exc_tb
Return self. handle_error
WithContext (True ):
Raise RuntimeError ('error message handled ')
Print
WithContext (False ):
RaiseRuntimeError ('error message propagated ')
If the context manager can handle this exception, __exit _ () should return a true value to indicate that this exception does not need to be propagated. If false is returned, _ exit _ () is returned and the exception is thrown again. The execution result is as follows:
# Pythoncontextlib_api_error.py
_ Init _ (True)
_ Enter __()
_ Exit __()
Exc_type = <type 'exceptions. runtimeerror'>
Exc_val = error message handled
Exc_tb = <traceback object at 0xb7691504>
_ Init _ (False)
_ Enter __()
_ Exit __()
Exc_type = <type 'exceptions. runtimeerror'>
Exc_val = error message propagated
Exc_tb = <traceback object at 0xb769157c>
Traceback (most recent call last ):
File "contextlib_api_error.py", line 30, in <module>
Raise RuntimeError ('error messagepropagated ')
RuntimeError: error message propagated
3.4.2 from generator to context Manager
The traditional method of creating a context manager is to compile a class containing the _ enter _ () and _ exit _ () methods, which is not difficult. However, in some cases, writing all the code in a few contexts is an extra burden. In these cases, you can use the contextmanager () modifier to convert a generator function to the context manager.
#! /Usr/bin/envpython
# Encoding: UTF-8
#
# Copyright (c) 2008 Doug Hellmann All rights reserved.
#
"""
$ Id $
"""
# End_pymotw_header
Importcontextlib
@ Contextlib. contextmanager
Defmake_context ():
Print 'entering'
Try:
Yield {}
Failed t RuntimeError, err:
Print 'error: ', err
Finally:
Print 'existing'
Print 'normal :'
Withmake_context () as value:
Print 'inside with statement: ', value
Print '\ nHandled error :'
Withmake_context () as value:
Raise RuntimeError ('showing example ofhandling an error ')
Print '\ nUnhandled error :'
Withmake_context () as value:
Raise ValueError ('this exception is nothandled ')
The generator needs to initialize the context, generate a value with yield, and then clear the context. The generated value (if any) is bound to a variable in the as clause of the with statement. An exception in the with block will be thrown again in the generator so that it can be processed in the generator. Execution result:
# Pythoncontextlib_contextmanager.py
Normal:
Entering
Inside with statement :{}
Exiting
Handlederror:
Entering
ERROR: showing example of handling an error
Exiting
Unhandlederror:
Entering
Exiting
Traceback (most recent call last ):
File "contextlib_contextmanager.py", line 32, in <module>
Raise ValueError ('this exception is nothandled ')
ValueError: this exception is not handled
3.4.3 nested Context
In some cases, you must manage multiple contexts at the same time (for example, copying data between the input and output file handles ). Therefore, with statements can be nested. However, if the external context does not require separate blocks, nested with statements only increase the indentation level without providing any practical benefits. With nested (), you can use a with statement to implement context nesting.
#! /Usr/bin/envpython
# Encoding: UTF-8
#
# Copyright (c) 2008 Doug Hellmann All rights reserved.
#
"""
$ Id $
"""
# End_pymotw_header
Importcontextlib
@ Contextlib. contextmanager
Defmake_context (name ):
Print 'entering: ', name
Yield name
Print 'exiting: ', name
Withcontextlib. nested (make_context ('A '),
Make_context ('B') as (A, B ):
Print 'inside with statement: ', A, B
When a program is executed, it will exit the context in reverse order of its entry into the context.
# Pythoncontextlib_nested.py
Entering:
Entering: B
Inside withstatement: A B
Exiting: B
Exiting:
Nested () is discarded in Python 2.7 and later versions, because with statements in these versions directly support nesting.
#! /Usr/bin/envpython
# Encoding: UTF-8
#
# Copyright (c) 2008 Doug Hellmann All rights reserved.
#
"""
$ Id $
"""
# End_pymotw_header
Importcontextlib
@ Contextlib. contextmanager
Defmake_context (name ):
Print 'entering: ', name
Yield name
Print 'exiting: ', name
Withmake_context ('A') as A, make_context ('B') as B:
Print 'inside with statement: ', A, B
Each context manager and the as clause (optional) are separated by a comma. The effect is similar to using nested (), but it avoids some boundary situations related to error handling that cannot be correctly implemented by nested.
# Pythoncontextlib_nested_with.py
Entering:
Entering: B
Inside withstatement: A B
Exiting: B
Exiting:
3.4.4 close the opened handle
The file class directly supports the context manager API, but other objects that open the handle do not support this API. The example in the standard library document of contextlib is an object returned by urllib. urlopen. There are also some legacy classes that use the close () method instead of the context manager API. To disable the handle, you need to use closing () to create a context manager for it.
#! /Usr/bin/envpython
# Encoding: UTF-8
#
# Copyright (c) 2008 Doug Hellmann All rights reserved.
#
"""
$ Id $
"""
# End_pymotw_header
Importcontextlib
ClassDoor (object ):
Def _ init _ (self ):
Print '_ init __()'
Def close (self ):
Print 'close ()'
Print 'normalexample :'
Withcontextlib. closing (Door () as door:
Print 'inside with statement'
Print '\ nError handling example :'
Try:
With contextlib. closing (Door () as door:
Print 'raising from inside with statement'
Raise RuntimeError ('error message ')
Extends texception, err:
Print 'Had an error: ', err
Whether or not there is an error in the with block, this handle will be closed. Execution result:
# Pythoncontextlib_closing.py
NormalExample:
_ Init __()
Inside with statement
Close ()
Errorhandling example:
_ Init __()
Raising from inside with statement
Close ()
Had an error: error message
Author: oychw