在"except"语句或上下文管理器中,"as"绑定的范围是什么



我知道python通常只为类、函数等创建新的作用域,但我对try/except块或上下文管理器中的as语句感到困惑。在块内部分配的变量可以在块外部访问,这是有道理的,但与as绑定的变量本身则不然。

所以这失败了:

try:
raise RuntimeError()
except RuntimeError as error:
pass
print(repr(error))

但这成功了:

try:
raise RuntimeError()
except RuntimeError as e:
error = e
print(repr(error))

as绑定的变量发生了什么,为什么不应用正常的python作用域规则?PEP表示它只是一个正常绑定的python变量,但事实并非如此。

如PEP 3110以及当前文档中所述,在except块中与as绑定的变量在块末尾被明确且特别地清除,即使它们共享相同的本地作用域。这提高了垃圾收集的即时性。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()
>>> 

行为特定于except块,而不是特定于as关键字。

这是一个记录在案的异常,*特别适用于try-except语句,来自语言引用:

使用作为目标分配异常时,会在除外条款的末尾。这就好像:

except E as N:
foo

已翻译为

except E as N:
try:
foo
finally:
del N

这意味着必须将异常分配给不同的名称能够在except子句之后引用它。已清除异常因为有了回溯,它们就形成了一个引用与堆栈帧循环,使该帧中的所有局部保持活动状态直到下一次垃圾回收发生。

如前所述,发生这种情况的原因是为了防止参考周期。

注意,此仅适用于try - except复合语句,as不是独立语句,它是不同的独立复合语句(withtry-except(的一部分

最新更新