|
Context Manager
In using the Python programming, you can often encounter this situation: there is a special block of statements before executing the block of statements need to perform some preparatory actions; when the block of statements executed, ending the need to continue to perform some action.
For example: When the need to manipulate the file or database, you first need to obtain a file handle or a database connection object, when executing the corresponding operation, need to do to release the file handle or close the database connection action.
As another example, when a multithreaded program requires access to critical resources, the thread first need to acquire the mutex when the execution is complete and ready to exit the critical section, it is necessary to release the mutex.
For these cases, Python provides a context manager (Context Manager) concept may be defined by the context manager / control ready to move blocks of code executed before, and ending after the implementation of the action.
Context Management Protocol
So in Python how to achieve a context manager do? Here, again referred to the two "magic method", __ enter__ and __exit__, the following is specific information about these two methods.
__enter __ (self) Defines what the context manager should do at the beginning of the block created by the with statement. Note that the return value of __enter__ is bound to the target of the with statement, or the name after the as.
__exit __ (self, exception_type, exception_value, traceback) Defines what the context manager should do after its block has been executed (or terminates). It can be used to handle exceptions, perform cleanup, or do something always done immediately after the action in the .. block If the block executes successfully, exception_type, exception_value, and traceback will be None Otherwise, you can choose to handle the exception or let the user handle it; if you want to handle it, make sure __exit__ returns True after all is said and done. If you do not want the exception to be handled by the context manager, just let it happen.
That is, when we need to create a context manager type, it needs to achieve __enter__ and __exit__ method, which method is called context management protocol (Context Manager Protocol), defines the context of operating a time surroundings.
with statement
In Python, you can easily use with statement context managers, with statement can enter a runtime context (__enter__ execution method) before the block of code to run, and quit the context at the end of the code block (execution __exit_ _method).
With statement syntax is as follows:
with context_expr [as var]:
with_suite
context_expr support the context management protocol object, that is, the context manager object is responsible for maintaining context
as var is an optional part, saved by the context manager object variable manner
with_suite block of statements that need to be placed in the context of the implementation of
In the Python built-in types, many types are supported by the context management protocol, such as file, thread.LockType, threading.Lock like. Here we have to file type, for example, look at using with statement.
statements with simplified file operations
When you need to write a file, usually in the following way. Code using the try-finally statement block, even if an exception occurs, but also to ensure close the file handle.
logger = open ( "log.txt", "w")
try:
logger.write ( 'Hello')
logger.write ( 'World')
finally:
logger.close ()
print logger.closed
In fact, Python's built-in file type is supported by the context management protocol, it can be directly through the built-in function dir () to view the file support methods and properties:
>>> Print dir (file)
[ '__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '
__getattribute__ ',' __hash__ ',' __init__ ',' __iter__ ',' __new__ ',' __reduce__ ',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclass
hook__ ',' close ',' closed ',' encoding ',' errors ',' fileno ',' flush ',' isatty ','
mode ',' name ',' newlines', 'next', 'read', 'readinto', 'readline', 'readlines',
'Seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']
>>>
Therefore, it can be simplified by the statement with the above code, the effect of the code is the same, but with the use of the code more concise statement:
with open ( "log.txt", "w") as logger:
logger.write ( 'Hello')
logger.write ( 'World')
print logger.closed
Custom Context Manager
For a custom type, you can achieve __enter__ and __exit__ ways to achieve Context Manager.
Look at the following code, the code defines a MyTimer type, the context manager can achieve the timing function code block:
import time
class MyTimer (object):
def __init __ (self, verbose = False):
self.verbose = verbose
def __enter __ (self):
self.start = time.time ()
return self
def __exit __ (self, * unused):
self.end = time.time ()
self.secs = self.end - self.start
self.msecs = self.secs * 1000
if self.verbose:
print "elapsed time:% f ms"% self.msecs
Use this in conjunction with the following statement context managers:
def fib (n):
if n in [1, 2]:
return 1
else:
return fib (n-1) + fib (n-2)
with MyTimer (True):
print fib (30)
Exception handling and __exit__
Using the context manager, if the block of code (with_suite) had abnormal, __ exit__ method will be called, and they have different methods __exit__ exception handling.
When exiting the current context __exit__ method runs, and returns a Boolean value that indicates the Boolean value "if the code block (with_suite) arising from the implementation of the exception, which if need be ignored."
1. __exit__ returns False, re-throw (re-raised) to the upper abnormal
Modify the previous example, type in MyTimer added a parameter "ignoreException" to indicate whether a context manager ignores exception code block (with_suite) produced.
import time
class MyTimer (object):
def __init __ (self, verbose = False, ignoreException = False):
self.verbose = verbose
self.ignoreException = ignoreException
def __enter __ (self):
self.start = time.time ()
return self
def __exit __ (self, * unused):
self.end = time.time ()
self.secs = self.end - self.start
self.msecs = self.secs * 1000
if self.verbose:
print "elapsed time:% f ms"% self.msecs
return self.ignoreException
try:
with MyTimer (True, False):
raise Exception ( "Ex4Test")
except Exception, e:
print "Exception (% s) was caught"% e
else:
print "No Exception happened"
Running this code will get the following result, __exit__ method returns False, so the code block (with_suite) The exception will be thrown to continue the upper code.
2. __exit__ return Ture, code blocks (with_suite) The exception is ignored
Code to __exit__ returns is True:
try:
with MyTimer (True, True):
raise Exception ( "Ex4Test")
except Exception, e:
print "Exception (% s) was caught"% e
else:
print "No Exception happened"
Run the result becomes the following case, the code block (with_suite) anomalies were ignored, the code continues to run
Be careful to use __exit__ return Ture situation, unless it is clear why.
3. For more information about abnormal function of the full signature by __exit__
For __exit__ function, its full signature below, that is, by this function can get more information of an abnormality.
__exit __ (self, exception_type, exception_value, traceback)
Continue to modify the above example __exit__ function as follows:
def __exit __ (self, exception_type, exception_value, traceback):
self.end = time.time ()
self.secs = self.end - self.start
self.msecs = self.secs * 1000
if self.verbose:
print "elapsed time:% f ms"% self.msecs
print "exception_type:", exception_type
print "exception_value:", exception_value
print "traceback:", traceback
return self.ignoreException
The operation results, it shows more information related to the abnormality
to sum up
This article describes the Python context managers, as well as how to use the statement in conjunction with the context manager.
To sum up the flow of execution with the statement:
Executive context_expr to get a context manager object
Call context manager __enter __ () method
If there are as var clause, then __enter __ () method returns the value assigned to var
Code block is executed with_suite
Call context manager __exit __ () method, if with_suite an exception, then the exception type, value and traceback will be passed as parameters to __exit __ (), otherwise pass three None
If with_suite an exception, and __exit __ () return value is equal to False, then this exception will be thrown back to the top
If with_suite an exception, weapons __exit __ () return value is equal to True, then the exception is ignored, continue to implement the code behind
In many cases, with statements can simplify the code, and to increase the robustness of the code. |
|
|
|