Python &引用;除Foo as bar外“;原因“;酒吧;从范围中删除

Python &引用;除Foo as bar外“;原因“;酒吧;从范围中删除,python,python-3.x,scoping,Python,Python 3.x,Scoping,给定以下代码: msg = "test" try: "a"[1] except IndexError as msg: print("Error happened") print(msg) 有人能解释一下为什么在Python3中会出现以下输出吗 发生错误 回溯(最近一次呼叫最后一次): 文件“test.py”,第6行,在 打印(msg) NameError:未定义名称“msg” 是,一旦引发异常并为新异常对象分配了msg,原始对象就不再有引用,因此被删除。新的异常对象在离开exc

给定以下代码:

msg = "test"
try:
    "a"[1]
except IndexError as msg:
    print("Error happened")
print(msg)
有人能解释一下为什么在Python3中会出现以下输出吗

发生错误
回溯(最近一次呼叫最后一次):
文件“test.py”,第6行,在
打印(msg)
NameError:未定义名称“msg”

是,一旦引发异常并为新异常对象分配了
msg
,原始对象就不再有引用,因此被删除。新的异常对象在离开
except
块时也会被删除

您可以通过覆盖对象的
方法和分配给
msg
的异常来验证它:

class A:
    def __del__(self):
        print('object deleted')
class E(Exception):
    def __del__(self):
        print('exception deleted')
msg = A()
try:
    raise E()
except E as msg:
    print("Error happened")
这将产生:

object deleted
Error happened
exception deleted
NameError: name 'msg' is not defined

except子句中的
msg
与第一行的
msg
在同一范围内

但是:

当使用
作为目标分配异常时,将在
except子句的结尾。这就好像

except E as N:
    foo
翻译成

except E as N:
    try:
        foo
    finally:
        del N
这意味着必须将该异常分配给要处理的其他名称 可以在except子句之后引用它。例外情况已清除 因为有了回溯,它们就形成了一个引用 循环堆栈帧,使该帧中的所有局部变量保持活动状态 直到下一次垃圾回收发生


因此,您在异常处理程序中“overwrite
msg
”,退出该处理程序将删除变量以清除回溯引用循环。

异常块删除块末尾捕获的变量,但它们没有自己的作用域。因此,事件的顺序如下:

1)
msg
设置为本地范围内的某个字符串

2)
msg
被设置为与1在同一本地范围内的索引器对象

3) 异常块结束时,从本地作用域中删除
msg


4)
msg
不再在本地作用域中定义,因此访问它的尝试失败

这特别回答了在
之后如何以及为什么删除先前的
msg
的问题,除了:
,包括对文档的引用,因此我认为它应该是可接受的答案。@LightnessRacesinOrbit是的,这确实很奇怪。我的意思是:如果你想要一个新的作用域,那么就创建一个新的作用域,不要终止对第一个
msg
的引用。如果您不想要一个新的作用域,那么为什么要终止异常引用呢?它一点也不不不可靠。通过使用
除了。。。作为msg
您正在将
msg
绑定到异常,该异常将删除对原始对象的所有引用。相反,如果<代码>除了。。。因为使用了m
,所以不会产生任何问题,因为原始绑定
msg
没有在except块中修改。@Shamtam正如Giacomo解释的那样,它肯定是不可靠的。Python的工作方式是在现有范围内重新绑定
msg
。但是
msg
的范围存在于
try
块之外(如果没有引发异常,则将继续存在)。运行时条件决定变量(应该是静态的)的范围这一事实是系统类型的CRASSubversion。由于Python是动态类型化的,这当然是可行的,但它仍然很奇怪。而且,Python2的处理方式完全不同,正如预期的那样。@Shamtam“这就是Python的工作方式”:这当然是真的。没有人否认这一点。但这并不意味着人们不应该认为Python是不可靠的。“其他流行语言”中的作用域规则允许使用这些语言的程序员避免在到达except块(或类似块)之前跟踪所用名称的心理负担,从而能够避免在块中使用现有名称;解释器或编译器为它们执行此操作。原因
msg
末尾被删除,除了
块与作用域无关。他们希望清除在Python 3中添加
\uuu traceback\uuu
属性所创建的引用循环。看见这确实令人困惑,有一个强有力的论据认为Python应该停止尝试支持在关闭GC的情况下运行,但这不是范围问题。