我知道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
不是独立语句,它是不同的独立复合语句(with
和try-except
(的一部分