Home > Article > Backend Development > Detailed explanation of using the with keyword in Python
This article mainly introduces the relevant information on the detailed use of the with keyword in Python. In Python, the with keyword is a good thing to manage the context protocol object for you. Friends who need it You can refer to the following
">
In Python 2.5, the with keyword was added. It makes the commonly used try...except...finally... pattern very convenient Reuse. Take a look at the most classic example:
with open('file.txt') as f: content = f.read()
In this code, no matter what happens during the execution of the code block in with, the file will eventually be closed if the code block is executed. If an exception occurs during the process, the program will first close the opened file before the exception is thrown.
Look at another example before initiating a database transaction request. When , code like this is often used:
db.begin() try: # do some actions except: db.rollback() raise finally: db.commit()
If the operation of initiating a transaction request is changed to support the with keyword, then code like this is enough:
with transaction(db): # do some actions
Below, the execution process of with is explained in detail, and the above code is implemented in two common ways.
The general execution process of withA basic with.
Expression, its structure is as follows: with EXPR as VAR:
BLOCK
Among them: EXPR can be any expression; as VAR is optional. Its general execution process is as follows:
#Call the enter() method of the context manager.
If the with expression contains as VAR, the return value of EXPR is assigned to VAR.
mgr = (EXPR) exit = type(mgr).exit # 这里没有执行 value = type(mgr).enter(mgr) exc = True try: try: VAR = value # 如果有 as VAR BLOCK except: exc = False if not exit(mgr, *sys.exc_info()): raise finally: if exc: exit(mgr, None, None, None)This process has several details:
After an exception occurs in BLOCK, if the exit() method returns a value that can be regarded as True, then the exception will not be thrown, and the subsequent code will continue to execute.
Implementing the context manager class
The first method is to implement a class that contains an instance
Attributesdb and the methods required by the context manager 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 execution process of with, this implementation is easy to understand. The implementation method introduced below is much more complicated to understand.
Using
GeneratorsIn Python's standard library, there is a decorator that can get the context manager through the generator. The implementation process using the generator decorator is as follows:from contextlib import contextmanager @contextmanager def transaction(db): db.begin() try: yield db except: db.rollback() raise else: db.commit()At first glance, this implementation is simpler, but its mechanism is more complex. Take a look at its execution process:
After the Python interpreter recognizes the yield keyword, def will create a generator Function
Replace the regular function (in the class definition I prefer to use functions instead of methods). The decorator contextmanager is called and returns a helper method, which will generate a GeneratorContextManager instance after being called. Finally, the EXPR in the with expression calls the helper function returned by the contentmanager decorator.with 表达式调用实例对象的上下文管理器的 enter() 方法。
enter() 方法中会调用这个生成器的 next() 方法。这时候,生成器方法会执行到 yield db 处停止,并将 db 作为 next() 的返回值。如果有 as VAR ,那么它将会被赋值给 VAR 。
with 中的 BLOCK 被执行。
BLOCK 执行结束后,调用上下文管理器的 exit() 方法。 exit() 方法会再次调用生成器的 next() 方法。如果发生 StopIteration 异常,则 pass 。
如果没有发生异常生成器方法将会执行 db.commit() ,否则会执行 db.rollback() 。
再次看看上述过程的代码大致实现:
def contextmanager(func): def helper(*args, **kwargs): return GeneratorContextManager(func(*args, **kwargs)) return helper class 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
总结
Python的 with 表达式包含了很多Python特性。花点时间吃透 with 是一件非常值得的事情。
一些其他的例子
锁机制
@contextmanager def locked(lock): lock.acquired() try: yield finally: lock.release()
标准输出重定向
@contextmanager def stdout_redirect(new_stdout): old_stdout = sys.stdout sys.stdout = new_stdout try: yield finally: sys.stdout = old_stdout with open("file.txt", "w") as f: with stdout_redirect(f): print "hello world"
The above is the detailed content of Detailed explanation of using the with keyword in Python. For more information, please follow other related articles on the PHP Chinese website!