给出以下代码:
msg = "test"
try:
"a"[1]
except IndexError as msg:
print("Error happened")
print(msg)
有人可以解释为什么这会在Python 3中导致以下输出吗?
Error happened
Traceback (most recent call last):
File "test.py", line 6, in <module>
print(msg)
NameError: name 'msg' is not defined
答案 0 :(得分:50)
msg
在except子句中与第一行msg
处于相同范围。
但是in Python 3 we have this new behavior too:
使用
as target
分配了异常后,该异常将在以下位置清除 except子句的末尾。好像是except E as N: foo
已翻译为
except E as N: try: foo finally: del N
这意味着必须将异常分配给其他名称 能够在except子句之后引用它。异常已清除 因为附加了追溯功能,它们形成了参考 循环使用堆栈框架,使该框架中的所有本地人保持活动状态 直到下一次垃圾回收发生为止。
因此,您在异常处理程序中“覆盖msg
”,退出处理程序将删除该变量以清除回溯引用周期。
答案 1 :(得分:33)
是的,一旦引发异常并为msg
分配了新的异常对象,原始对象就不再具有引用,因此将被删除。新的异常对象离开except
块后也会被删除。
您可以通过覆盖对象的__del__
方法和分配给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
答案 2 :(得分:7)
Exception块在块的末尾删除了捕获的变量,但是它们没有自己的作用域。因此,事件的顺序如下:
1)msg
设置为本地范围内的某些字符串
2)msg
设置为与1相同的本地范围内的IndexError对象
3)异常块结束后,msg
从本地作用域中删除
4)msg
不再在本地范围内定义,因此访问它的尝试失败