在 finally 块中使用异常变量
Use exception variable in finally block
当运行这个例子func:
from typing import Tuple, Any, Optional
def func() -> Tuple[Any, Optional[Exception]]:
exc = None
ret = None
try:
# code here, if successful assign result to `ret`
ret = "Result"
# comment this line out and the code works
raise Exception
except Exception as exc:
exc.__traceback__ = None
# Error logging here
pass
finally:
return ret, exc
print(func()) # expected: ("Result", <Exception instance>)
最后一行 (return ret, exc
) 引发 UnboundLocalError: local variable 'exc' referenced before assignment
即使 exc
明确绑定在函数的第一行 (exc = None
) 中。这可以通过像这样更改 except
-子句来解决:
except Exception as exc1:
exc = exc1
exc.__traceback__ = None
# Error logging here
pass
问题:
- 是否可以避免使用另一个变量(在我的示例中
exc1
),同时仍然避免使用 UnboundLocalError
?
- 为什么
except <Exception> as <var>
语句“吞噬”了已经定义的局部变量?
这种情况在8.4. The try statement中有描述:
When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if
except E as N:
foo
was translated to
try:
foo
finally:
del N
This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.
当运行这个例子func:
from typing import Tuple, Any, Optional
def func() -> Tuple[Any, Optional[Exception]]:
exc = None
ret = None
try:
# code here, if successful assign result to `ret`
ret = "Result"
# comment this line out and the code works
raise Exception
except Exception as exc:
exc.__traceback__ = None
# Error logging here
pass
finally:
return ret, exc
print(func()) # expected: ("Result", <Exception instance>)
最后一行 (return ret, exc
) 引发 UnboundLocalError: local variable 'exc' referenced before assignment
即使 exc
明确绑定在函数的第一行 (exc = None
) 中。这可以通过像这样更改 except
-子句来解决:
except Exception as exc1:
exc = exc1
exc.__traceback__ = None
# Error logging here
pass
问题:
- 是否可以避免使用另一个变量(在我的示例中
exc1
),同时仍然避免使用UnboundLocalError
? - 为什么
except <Exception> as <var>
语句“吞噬”了已经定义的局部变量?
这种情况在8.4. The try statement中有描述:
When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if
except E as N: foo
was translated to
try: foo finally: del N
This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.