1.上下文管理协议
A context manager is an object that defines the runtime context to be established when executing a with statement. The context manager handles the entry into, and the exit from, the desired runtime context for the execution of the block of code. Context managers are normally invoked using the with statement (described in section The with statement), but can also be used by directly invoking their methods.
Typical uses of context managers include saving and restoring various kinds of global state, locking and unlocking resources, closing opened files, etc.
上下文管理器是一个对象,它定义在执行with语句时要建立的运行时上下文。 上下文管理器处理进入和退出所需运行时上下文以执行代码块。 通常使用with语句调用上下文管理器(在with语句一节中描述),但也可以通过直接调用它们的方法来使用。
上下文管理器的典型用途包括保存和恢复各种全局状态,锁定和解锁资源,关闭打开的文件等。
上下文管理器是用来定义执行with语句时建立的运行时上下文的一个对象,通过调用对象的__ enter__和__ exit__ 方法来实现
2.__ enter__()
object.__ enter__(self)
Enter the runtime context related to this object. The with statement will bind this method’s return value to the target(s) specified in the as clause of the statement, if any.
进入对象的运行时上下文,with语句会把这个方法的返回值赋给as指定的变量.
3.__ exit__
object.__ exit__(self, exc_type, exc_value, traceback)
Exit the runtime context related to this object. The parameters describe the exception that caused the context to be exited. If the context was exited without an exception, all three arguments will be None.
If an exception is supplied, and the method wishes to suppress the exception (i.e., prevent it from being propagated), it should return a true value. Otherwise, the exception will be processed normally upon exit from this method.
Note that __ exit__() methods should not reraise the passed-in exception; this is the caller’s responsibility.
退出对象的运行时上下文,参数描述了导致上下文退出的异常信息.当正常退出时,三个参数都为None, 如果异常发生,则参数记录异常信息:exc_type(异常类型), exc_value(异常信息), traceback(异常追踪).
如果希望exit阻止异常报出, 那应该返回True(返回True则正常执行with后面的语句). 否则exit运行结束后会正常抛出异常信息.
注意,exit方法不应该重新抛出被传入的异常, 这是调用者的责任(?)
使用示例:
class Context:
def __init__(self, name):
self.name = name
def __enter__(self):
print('enter running')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit running')
print(exit, exc_type, exc_val, exc_tb, sep='\n')
with Context('sabi') as t:
print(t.name)
print(t.__dict__)
print('hhahahah')
#result
enter running
sabi
{'name': 'sabi'}
exit running
Use exit() or Ctrl-Z plus Return to exit
None
None
None
hhahahah
4.with语句
The with statement is used to wrap the execution of a block with methods defined by a context manager (see section With Statement Context Managers). This allows common try…except…finally usage patterns to be encapsulated for convenient reuse.
with语句利用上下文管理器来包装要执行的语句块, 这样可以将try,except等使用模式封装起来以便重用.
with语句执行流程:
The execution of the with statement with one “item” proceeds as follows:
1.The context expression (the expression given in the with_item) is evaluated to obtain a context manager.
评估上下文表达式以获得上下文管理器
2.The context manager’s __ exit__() is loaded for later use.
3.The context manager’s __ enter__() method is invoked.
4.If a target was included in the with statement, the return value from __ enter__() is assigned to it.
Note:
The with statement guarantees that if the __ enter__() method returns without an error, then __ exit__() will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 6 below.
注意:enter的返回结果赋值给with指定的变量时出错, 则视为在执行with下的语句块时出错,exit依然会触发.
5.The suite is executed.
6.The context manager’s __ exit__() method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as arguments to __ exit__(). Otherwise, three None arguments are supplied.
If the suite was exited due to an exception, and the return value from the __ exit__() method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following the with statement.
If the suite was exited for any reason other than an exception, the return value from __ exit__() is ignored, and execution proceeds at the normal location for the kind of exit that was taken.
4.2多个with叠加
With more than one item, the context managers are processed as if multiple with statements were nested:
with A() as a, B() as b:
suite
# is equivalent to
with A() as a:
with B() as b:
suite