Jos*_*uaF 7 python contextmanager
我知道一般来说 python 只会为类、函数等创建新的作用域,但我对astry/ except 块或上下文管理器中的语句感到困惑。在块内部分配的变量可以在块外部访问,这是有道理的,但是与as则不然。
所以这失败了:
try:
raise RuntimeError()
except RuntimeError as error:
pass
print(repr(error))
Run Code Online (Sandbox Code Playgroud)
但这成功了:
try:
raise RuntimeError()
except RuntimeError as e:
error = e
print(repr(error))
Run Code Online (Sandbox Code Playgroud)
与 绑定的变量发生了什么as,为什么正常的 python 作用域规则不适用?PEP表明它只是一个正常绑定的 python 变量,但情况似乎并非如此。
正如PEP 3110以及当前文档as中所解释的,块中绑定的变量except会在块末尾显式且专门地清除,即使它们共享相同的本地范围。这提高了垃圾收集的即时性。该as语法最初不适用于 2.x 中的异常;它被向后移植到 2.6,但旧的语义被保留。
这同样不适用于块with:
>>> from contextlib import contextmanager
>>> @contextmanager
... def test():
... yield
...
>>> with test() as a:
... pass
...
>>> a # contains None; does not raise NameError
>>>
>>> def func(): # similarly within a function
... with test() as a:
... pass
... return a
...
>>> func()
>>>
Run Code Online (Sandbox Code Playgroud)
该行为特定于except块,而不是特定于as关键字。
这是正常规则的记录例外,*特别适用于try-except语句,来自语言参考:
当使用作为目标分配异常时,它会在 except 子句的末尾被清除。这就像:
Run Code Online (Sandbox Code Playgroud)except E as N: foo被翻译成
Run Code Online (Sandbox Code Playgroud)except E as N: try: foo finally: del N这意味着必须为异常分配一个不同的名称,以便能够在 except 子句之后引用它。异常会被清除,因为附加了回溯,它们与堆栈帧形成了一个引用循环,使该帧中的所有局部变量保持活动状态,直到发生下一次垃圾收集。
如前所述,发生这种情况的原因是为了防止引用循环。
注意,这仅适用于try - except复合语句,as不是独立语句,它是不同的独立复合语句(with和try-except)的一部分