This article mainly introduces detailed information about the use of the with keyword in Python. in Python, the with keyword is a good thing for you to manage and implement context protocol objects, for more information about how to use the with keyword in Python, refer to this article. in Python, the with keyword is a good thing for you to manage and implement context protocol objects, for more information, see
">
In Python 2.5, the with keyword is added. It makes the common try... try t... finally... mode easy to reuse. Let's look at a classic example:
with open('file.txt') as f: content = f.read()
In this code, no matter what happens to the code block in with during execution, the file will eventually be closed. If a code block has an exception during execution, the program closes the opened file before the exception is thrown.
Let's look at another example.
When initiating a database transaction request, code similar to this is often used:
db.begin()try: # do some actionsexcept: db.rollback() raisefinally: db.commit()
If you change the operation that initiates a transaction request to support the with keyword, you can use code like this:
with transaction(db): # do some actions
The following describes in detail the with execution process and implements the above code in two common ways.
General with execution process
The structure of a basic with expression is as follows:
with EXPR as VAR: BLOCK
EXPR can be any expression, and as VAR is optional. The general execution process is as follows:
Calculate EXPR and obtain a context manager.
The exit () method of the context manager is saved for subsequent calls.
Call the enter () method of the context manager.
If the with expression contains as VAR, the return value of EXPR is assigned to VAR.
Execute the expression in the BLOCK.
Call the exit () method of the context manager. If an exception occurs during BLOCK execution and causes the program to exit, the type, value, and traceback (sys. the return value of exc_info () is passed as a parameter to the exit () method. Otherwise, three None are passed.
The process is represented in code as follows:
Mgr = (EXPR) exit = type (mgr ). exit # value = type (mgr) is not executed here ). enter (mgr) exc = Truetry: try: VAR = value # if there is as var block partition T: exc = False if not exit (mgr, * sys. exc_info (): raisefinally: if exc: exit (mgr, None)
This process has several details:
If the context manager does not have any method in enter () or exit (), the interpreter throws an AttributeError.
When an exception occurs in the BLOCK, if the exit () method returns a value that can be considered as True, the exception will not be thrown and subsequent code will continue to be executed.
Next, use two methods to implement the above process.
Implement the context manager class
The first method is to implement a class that contains an instance attribute db and the methods required by the context manager, such as enter () and exit ().
class transaction(object): def init(self, db): self.db = db def enter(self): self.db.begin() def exit(self, type, value, traceback): if type is None: db.commit() else: db.rollback()
After understanding the with execution process, this implementation method is easy to understand. The implementation method described below is much more complicated to understand.
Use the generator decorator
In The Python Standard Library, there is a modifier that can get the context manager through the generator. The implementation process of using the generator decorator is as follows:
from contextlib import contextmanager@contextmanagerdef transaction(db): db.begin() try: yield db except: db.rollback() raise else: db.commit()
At first glance, this implementation method is simpler, but its mechanism is more complex. Let's take a look at the execution process:
After the Python interpreter recognizes the yield keyword, def will create a generator function to replace the regular function (I like to replace the method with the function in addition to the class definition ).
Contextmanager is called and a help method is returned. after the contextmanager is called, a GeneratorContextManager instance is generated. In the end, EXPR in the with expression calls the help function returned by the contentmanager modifier.
The with expression calls transaction (db), which is actually a help function. The help function calls the generator function. the generator function creates a generator.
The help function passes the generator to GeneratorContextManager and creates an instance object of GeneratorContextManager as the context manager.
The with expression calls the enter () method of the context manager of the instance object.
The next () method of the generator is called in the enter () method. At this time, the generator method will stop at the yield db and use the db as the return value of next. If there is as VAR, it will be assigned to VAR.
The BLOCK in with is executed.
After the BLOCK is executed, call the exit () method of the context manager. The exit () method calls the next () method of the generator again. If a StopIteration exception occurs, pass.
If no exception occurs in the generator method, db. commit () is executed; otherwise, db. rollback () is executed ().
Let's take a look at the code implementation of the above process again:
def contextmanager(func): def helper(*args, **kwargs): return GeneratorContextManager(func(*args, **kwargs)) return helperclass GeneratorContextManager(object): def init(self, gen): self.gen = gen def enter(self): try: return self.gen.next() except StopIteration: raise RuntimeError("generator didn't yield") def exit(self, type, value, traceback): if type is None: try: self.gen.next() except StopIteration: pass else: raise RuntimeError("generator didn't stop") else: try: self.gen.throw(type, value, traceback) raise RuntimeError("generator didn't stop after throw()") except StopIteration: return True except: if sys.exc_info()[1] is not value: raise
Summary
The with expression in Python contains many Python features. Taking a moment to get familiar with is very worthwhile.
Some other examples
Lock mechanism
@contextmanagerdef locked(lock): lock.acquired() try: yield finally: lock.release()
Standard output redirection
@contextmanagerdef stdout_redirect(new_stdout): old_stdout = sys.stdout sys.stdout = new_stdout try: yield finally: sys.stdout = old_stdoutwith open("file.txt", "w") as f: with stdout_redirect(f): print "hello world"
The above is the detailed description of the with keyword in Python. For more information, see other related articles in the first PHP community!