除外子句删除局部变量 [英] except-clause deletes local variable

查看:49
本文介绍了除外子句删除局部变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

exc = 无尝试:引发异常除了例外作为 exc:经过# ...打印(不包括)

<块引用>

NameError: name 'exc' 未定义

这曾经在 Python2 中工作.为什么会变成这样?如果我至少可以重新分配给 exc,类似于类级别的属性

class Foo(object):酒吧 = 酒吧

但这也不起作用:

exc = 无尝试:引发异常除了例外作为 exc:exc = exc

有什么好的提示可以实现相同的目标吗?我不想写这样的东西:

exc = 无尝试:引发异常(foo")除了作为 e 的例外:exc = e# ...打印(不包括)

解决方案

try 语句明确限制了绑定异常的范围,以防止循环引用导致它泄漏.请参阅try 语句文档:

<块引用>

当一个异常被分配为目标时,它在except子句的末尾被清除.

[...]

这意味着必须为异常分配一个不同的名称,以便能够在 except 子句之后引用它.异常被清除是因为通过附加到它们的回溯,它们与堆栈帧形成一个引用循环,使该帧中的所有局部变量保持活动状态,直到下一次垃圾回收发生.

强调我的;请注意,您唯一的选择是将异常绑定到新名称.

在 Python 2 中,异常没有对回溯的引用,这就是更改的原因.

然而,即使在 Python 2 中,您也会被明确警告清理回溯,请参阅 sys.exc_info():

<块引用>

警告:将 traceback 返回值分配给处理异常的函数中的局部变量将导致循环引用.这将防止同一函数中的局部变量或回溯引用的任何内容被垃圾收集.由于大多数函数不需要访问回溯,最好的解决方案是使用诸如 exctype, value = sys.exc_info()[:2] 之类的东西来仅提取异常类型和值.如果确实需要回溯,请确保在使用后将其删除(最好使用 try ... finally 语句完成)或在函数中调用 exc_info()本身不处理异常.

如果你重新绑定异常,你可能需要明确地清除回溯:

尝试:引发异常(foo")除了作为 e 的例外:exc = eexc.__traceback__ = 无

exc = None
try:
    raise Exception
except Exception as exc:
    pass

# ...

print(exc)

NameError: name 'exc' is not defined

This used to work in Python2. Why was it changed this way? If I could at least re-assign to exc, similar to class-level attributes

class Foo(object):
    Bar = Bar

but this does not make it work either:

exc = None
try:
    raise Exception
except Exception as exc:
    exc = exc

Any good hints to achieve the same? I'd prefer not to write something like this:

exc = None
try:
    raise Exception("foo")
except Exception as e:
    exc = e

# ...

print(exc)

解决方案

The try statement explictily limits the scope of the bound exception, to prevent circular references causing it to leak. See the try statement documentation:

When an exception has been assigned using as target, it is cleared at the end of the except clause.

[...]

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.

Emphasis mine; note that your only option is to bind the exception to a new name.

In Python 2, exceptions did not have a reference to the traceback, which is why this was changed.

However, even in Python 2, you are explicitly warned about cleaning up tracebacks, see sys.exc_info():

Warning: Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. Since most functions don’t need access to the traceback, the best solution is to use something like exctype, value = sys.exc_info()[:2] to extract only the exception type and value. If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement) or to call exc_info() in a function that does not itself handle an exception.

If you do re-bind the exception, you may want to clear the traceback explicitly:

try:
    raise Exception("foo")
except Exception as e:
    exc = e
    exc.__traceback__ = None

这篇关于除外子句删除局部变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆