with 块中多个 __exit__ 调用的顺序是否始终是确定的?
Is the order of multiple __exit__ calls in a with-block always deterministic?
给定以下 ContextManager
类,这是以下示例中 __exit__
调用的顺序 - 声明的相反顺序。
有趣的是,__exit__
可以被调用多次。这在 2.7 的所有 Python 版本中都是确定性的吗?如果不是,从哪个版本这个顺序是可靠的确定性的?
a = A()
b = B()
c = C()
with a, b, c, a, a:
print("Start")
测试工具
from typing import ContextManager
class A(ContextManager):
def __exit__(self, __exc_type, __exc_value, __traceback):
print("A exit")
class B(ContextManager):
def __exit__(self, __exc_type, __exc_value, __traceback):
print("B exit")
class C(ContextManager):
def __exit__(self, __exc_type, __exc_value, __traceback):
print("C exit")
a = A()
b = B()
c = C()
with a, b, c, a, a:
print("Start")
Python 3.7+ 输出:
Start
A exit
A exit
C exit
B exit
A exit
同一行 with
上的多个上下文管理器被视为嵌套处理。所以这个:
with a, b, c:
stuff()
相当于:
with a:
with b:
with c:
stuff()
即__enter__
方法从左到右调用,当块结束时,__exit__
方法从右到左调用。
Is this deterministic in all versions of Python from 2.7?
是的,顺序明确since 2.7 at least:
with A() as a, B() as b:
... suite of statements ...
is equivalent to:
with A() as a:
with B() as b:
... suite of statements ...
你得到的顺序(从下往上读)
Start
A exit
A exit
C exit
B exit
A exit
确实是A、B、C、A、A,果然如所料。
给定以下 ContextManager
类,这是以下示例中 __exit__
调用的顺序 - 声明的相反顺序。
有趣的是,__exit__
可以被调用多次。这在 2.7 的所有 Python 版本中都是确定性的吗?如果不是,从哪个版本这个顺序是可靠的确定性的?
a = A()
b = B()
c = C()
with a, b, c, a, a:
print("Start")
测试工具
from typing import ContextManager
class A(ContextManager):
def __exit__(self, __exc_type, __exc_value, __traceback):
print("A exit")
class B(ContextManager):
def __exit__(self, __exc_type, __exc_value, __traceback):
print("B exit")
class C(ContextManager):
def __exit__(self, __exc_type, __exc_value, __traceback):
print("C exit")
a = A()
b = B()
c = C()
with a, b, c, a, a:
print("Start")
Python 3.7+ 输出:
Start
A exit
A exit
C exit
B exit
A exit
同一行 with
上的多个上下文管理器被视为嵌套处理。所以这个:
with a, b, c:
stuff()
相当于:
with a:
with b:
with c:
stuff()
即__enter__
方法从左到右调用,当块结束时,__exit__
方法从右到左调用。
Is this deterministic in all versions of Python from 2.7?
是的,顺序明确since 2.7 at least:
with A() as a, B() as b: ... suite of statements ...
is equivalent to:
with A() as a: with B() as b: ... suite of statements ...
你得到的顺序(从下往上读)
Start
A exit
A exit
C exit
B exit
A exit
确实是A、B、C、A、A,果然如所料。