Introduction
The WITH statement is a feature associated with exception handling that was introduced from Python 2.5 (the version 2.5 is to be imported through the From __future__ import with_statement), and defaults are available from version 2.6 (refer to What ' s New in Python 2.6? Described in the related section of the WITH statement). The With statement applies to situations where resources are accessed, ensuring that any exceptions that occur during use perform the necessary cleanup operations, freeing resources such as automatic shutdown of files after use, automatic acquisition and release of locks in threads, and so on.
Terms
To use the WITH statement, you first need to understand the concept of context manager. With the context manager, the WITH statement works.
The following is a set of concepts related to the context manager and the WITH statement.
Contextual Management Protocol (context Management Protocol): Contains methods __enter__ () and __exit__ (), supporting
The object of this Protocol is to implement both methods.
Context Manager: An object that supports a context management protocol that implements the
__enter__ () and __exit__ () methods. The context Manager defines the Run-time context to be established when executing the WITH statement.
is responsible for executing the Enter and exit operations in the context of the WITH statement block. The context manager is typically invoked with the WITH statement.
You can also use it by calling its methods directly.
Runtime contexts (runtime context): Created by the context manager, through the context Manager's __enter__ () and
__exit__ () method implementation, the __ENTER__ () method enters the Run-time context before the statement body executes, __exit__ () in
Exit from the Run-time context when the statement body finishes executing. The With statement supports the concept of a run-time context.
Context Expression: An expression in the With statement that follows the keyword with, the expression
To return a context manager object.
Statement Body (With-body): A block of code wrapped with a statement that invokes the context tube before executing the statement body
The __enter__ () method of the manager executes the __exit__ () method after the statement body is executed.
Basic grammar and working principle
The syntax format for the WITH statement is as follows:
Listing 1. Syntax format for with statement
With Context_expression [as Target (s)]:
with-body
Here context_expression to return a context manager object that is not assigned to target (s) in the AS clause, and if the AS clause is specified, the return value of the __enter__ () method of the context manager is assigned to target (s). Target (s) can be a single variable, or a tuple enclosed by "()" (cannot be a list of variables separated by only "," and must be added "()").
Python improves on some of the built-in objects, adds support for the context manager, and can be used with statements such as automatic shutdown of files, automatic acquisition and release of the lock, and so on. Assuming that you want to operate on a file, you can use the WITH statement with the following code:
Listing 2. Manipulating file objects with the WITH statement
With open (R ' Somefilename ') as Somefile: For line in
somefile:
print line
# ... more code
The WITH statement is used here to ensure that the open file handle is closed after the WITH statement has been executed, regardless of whether an exception occurred during the process of the file. If you use the traditional try/finally paradigm, use a code similar to the following:
Listing 3. Manipulating file Objects Try/finally
Somefile = open (R ' somefilename ')
try: For line in
somefile:
print line
# ... more code
finally:
Somefile.close ()
By comparison, using the WITH statement can reduce the amount of coding. There are modules threading, decimal, etc. that have been added to the context Management protocol support.
PEP 0343 describes the implementation of the WITH statement. The Execute procedure for the WITH statement resembles the following code block:
Listing 4. With statement execution procedure
Context_manager = Context_expression exit = Type (Context_manager). __exit__ value = Ty PE (Context_manager). __enter__ (context_manager) exc = true # True indicates normal execution, even if there are exceptions; False indicates that the exception is thrown again, and the exception needs to be handled TRY:TR
Y:target = value # If you use the AS clause With-body # execute with-body except: # An exception occurred during execution exc = False # if __exit__ returns TRUE, the exception is ignored; If returned False, the exception is thrown again # The exception is handled by the outer code if not exit (Context_manager, *sys.exc_info (
): Raise finally: # Normal exit, or exit by Statement-body Break/continue/return statement or ignore exception exit if exc: Exit (Context_manager, none, none, none) # Default returns None,none in Boolean context as False
Execute context_expression, build context manager Context_manager
Invokes the __enter__ () method of the context manager and assigns the return value of the __enter__ () method to target (s) in the AS clause if the AS clause is used
Execute Statement Body With-body
Regardless of whether an exception occurred during execution, the __exit__ () method of the context manager executes, and the __exit__ () method is responsible for performing cleanup work, such as freeing resources. If no exception occurs during execution, or if statement Break/continue/return is executed in the body of the statement, call __exit__ (none, none, none) as a parameter, or use SYS.EXC_ if an exception occurs during execution. Info Gets the exception information for the parameter call __exit__ (Exc_type, Exc_value, Exc_traceback)
When an exception occurs, if __exit__ (type, value, Traceback) returns FALSE, the exception is thrown again, allowing statement logic outside of with to handle the exception, which is a common practice; if True, ignore the exception and no longer process the exception
Custom Context Manager
Developers can customize the classes that support the context management protocol. The __enter__ () and __exit__ () two methods required by a custom context Manager to implement the context Management protocol:
CONTEXT_MANAGER.__ENTER__ (): Enters the context Manager's run-time context, called before the statement body executes. The WITH statement assigns the return value of the method to target in the AS clause, if the AS clause is specified
Context_manager.__exit__ (Exc_type, Exc_value, Exc_traceback): Exits the run-time context associated with the context manager, returning a Boolean value that indicates whether the exception that occurred was handled. Parameter represents the exception that caused the exit operation, and if no exception occurs when exiting, all 3 parameters are none. If an exception occurs, return
True indicates that an exception is not handled, or the exception is thrown again after exiting the method to be processed by code logic other than the WITH statement. If the method generates an exception internally, it replaces the exception generated by the statement in Statement-body. To handle an exception, do not display a throw-back exception, that is, the exception passed in by the parameter cannot be thrown back, and you can simply set the return value to False. The context management code then detects whether __exit__ () fails to handle the exception
The following is a simple example to demonstrate how to build a custom context manager. Note that the context manager must provide both the definition of the __enter__ () and the __exit__ () method, and any missing one will cause the Attributeerror;with statement to first check whether the __exit__ () method is provided, and then check if the definition of __ Enter__ () method.
Suppose there is a resource dummyresource, which needs to be allocated before access, then released after use, and the allocation can be placed in the __enter__ () method, and the release operation can be placed in the __exit__ () method. For simplicity, the current operation is only indicated by the print statement, and there is no actual resource allocation and release.
Listing 5. Customizing objects that support the WITH statement
Class Dummyresource:
def __init__ (self, Tag):
Self.tag = tag
print ' Resource [%s] '% tag
def __enter__ ( Self):
print ' [Enter%s]: Allocate resource. '% Self.tag
return Self # can be returned to different objects
def __exit__ (self, exc_ Type, Exc_value, EXC_TB:
print ' [Exit%s]: free resource. '% Self.tag
if EXC_TB is None:
print ' [Exit%s]: exited without exception. '% Self.tag
else:
print ' [Exit%s]: exited with exception raised. '% Self.tag
ret Urn False # can be omitted, and the default none is also considered false
The __enter__ () in Dummyresource returns a reference to itself that can be assigned to the target variable in the AS clause, and the type of the return value can be set to a different type depending on the actual needs, not necessarily the context Manager object itself.
The __exit__ () method detects the variable exc_tb, if not none, represents an exception, and False indicates that the exception needs to be handled by external code logic; Note that if no exception occurs, the default return value is None and is also considered False in a Boolean environment , but since no exception occurred, the three parameters of __exit__ () are none, and the context management code can detect this and do normal processing.
The following accesses the dummyresource in the WITH statement:
Listing 6. object with a custom supported with statement
With Dummyresource (' Normal '):
print ' [with-body] Run without exceptions. '
With Dummyresource (' with-exception '):
print ' [With-body] Run with Exception. '
Raise Exception
print ' [With-body] Run with Exception. Failed to finish statement-body! '
The execution result of the 1th with statement is as follows:
Listing 7. With statement 1 execution result
Resource [Normal]
[Enter Normal]: Allocate resource.
[With-body] Run without exceptions.
[Exit Normal]: free resource.
[Exit Normal]: exited without exception.
As you can see, execution executes the statement body With-body first, and then executes the __exit__ () method to release the resource.
The execution result of the 2nd with statement is as follows:
Listing 8. With statement 2 execution result
Resource [with-exception]
[Enter with-exception]: Allocate Resource.
[With-body] Run with exception.
[Exit with-exception]: free resource.
[Exit With-exception]: exited with Exception raised.
Traceback (most recent):
File "G:/demo", line <module>
raise Exception Exception
As you can see, when an exception occurs in With-body, the with-body is not finished, but the resource is guaranteed to be freed, and the resulting exception is captured by code logic outside of the WITH statement.
You can customize the context Manager to manage resources in a software system, such as database connections, access control for shared resources, and so on. The Python online documentation writing context managers provides a simple example of a contextual manager for managing database connections.
Contextlib Module
The Contextlib module provides 3 objects: Adorner ContextManager, function nested, and context manager closing. Using these objects, you can wrap existing generator functions or objects, add support for context management protocols, and avoid writing context managers specifically to support the WITH statement.
Adorner ContextManager
ContextManager is used to decorate a builder function, and after the builder function is decorated, a context manager is returned, and its __enter__ () and __exit__ () methods are provided by the ContextManager, not the previous iteration. A decorated generator function can produce only one value, otherwise it can cause an exception runtimeerror; the resulting value is assigned to target in the AS clause, if the AS clause is used. Let's look at a simple example.
Listing 9. Adorner ContextManager Use example
From contextlib import ContextManager
@contextmanager
def demo ():
print ' [Allocate resources] '
print ' Code before yield-statement executes in __enter__ '
yield ' * * * ContextManager Demo * * '
print ' code after yield-st Atement executes in __exit__ '
print '
/demo () as Value:
print ' assigned value:%s '% Valu E
The resulting output is as follows:
Listing 10. ContextManager using the sample to perform the results
[Allocate Resources]
Code before yield-statement executes in __enter__
assigned Value: * * * ContextManager demo
code after Yield-sta Tement executes in __exit__
[free resources]
As you can see, the statement before yield in the builder function executes in the __ENTER__ () method, and the statement after yield executes in __exit__ (), and the value that the yield produces is assigned to the values variable in the AS clause.
It should be noted that ContextManager only omitted the writing of __enter__ ()/__exit__ (), but was not responsible for the "get" and "clean" work of the resource; the "get" operation needs to be defined before the yield statement, the cleanup operation needs to be defined yield statement so that the WITH statement executes the __enter__ ()/__exit__ () method when executing these statements to obtain/release resources, that is, the necessary logical control to be implemented in the builder function, including the appropriate exception thrown when a resource access error occurs.
function Nested
Nested multiple context managers can be organized together to avoid the use of nested with statements.
Listing 11. Nested syntax
With nested (A (), B (), C ()) as (X, Y, Z):
# with-body code here
Similar to:
Listing 12. Nested execution process
With A () as X: With
B () as Y: With
C () as Z:
# with-body code here
Note that after an exception is thrown, if the __exit__ () method of a context manager returns FALSE for exception handling, the more Outer context manager does not detect the exception.
Context Manager closing
The implementation of closing is as follows:
Listing 13. Context Management Closing implementation
Class closing (object):
# Help Doc-Here
def __init__ (self, Thing):
self.thing = Thing
def __enter__ (self ): Return
self.thing
def __exit__ (self, *exc_info):
self.thing.close ()
The context manager assigns the wrapped object to the target variable of the AS clause, while ensuring that the open object is closed when the with-body is finished executing. The object wrapped by the closing context manager must provide the definition of the close () method, otherwise the Attributeerror error will be reported when executed.
Listing 14. Customizing objects that support closing
Class Closingdemo (object):
def __init__ (self):
Self.acquire ()
def acquire (self):
print ' Acquire Resources. '
def free (self):
print ' clean up any acquired. '
def close (self):
Self.free () and
closing (Closingdemo ()):
print ' Using resources '
The resulting output is as follows:
Listing 15. Customizing the output of a closing object
Acquire resources.
Using the
acquired.
Closing applies to objects that provide a close () implementation, such as a network connection, a database connection, etc., or you can perform the required resource cleanup work by using the interface Close () when customizing the class.