首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异常期间的Python函数局部变量作用域

异常期间的Python函数局部变量作用域
EN

Stack Overflow用户
提问于 2010-01-13 17:30:22
回答 3查看 2K关注 0票数 3

背景:我正在用Python语言对National Instruments的TestStand进行COM编程。如果对象没有正确“释放”,TestStand会报错(它会弹出一个“对象没有正确释放”的调试对话框)。在Python语言中释放TestStand COM对象的方法是确保所有变量不再包含该对象-例如,对它们执行del()操作,或者将它们设置为None。或者,只要变量是函数局部变量,当函数结束时,一旦变量超出作用域,对象就会被释放。

嗯,我在我的程序中遵循了这个规则,只要没有异常,我的程序就会正确地释放对象。但是如果我得到一个异常,我就会收到来自TestStand的"objects not released“消息。这似乎表明,当发生异常时,函数局部变量通常不会超出作用域。

下面是一个简化的代码示例:

代码语言:javascript
复制
class TestObject(object):
    def __init__(self, name):
        self.name = name
        print("Init " + self.name)
    def __del__(self):
        print("Del " + self.name)

def test_func(parameter):
    local_variable = parameter
    try:
        pass
#        raise Exception("Test exception")
    finally:
        pass
#        local_variable = None
#        parameter = None

outer_object = TestObject('outer_object')
try:
    inner_object = TestObject('inner_object')
    try:
        test_func(inner_object)
    finally:
        inner_object = None
finally:
    outer_object = None

如图所示,它显示了我所期望的结果:

代码语言:javascript
复制
Init outer_object
Init inner_object
Del inner_object
Del outer_object

但是如果我取消对raise Exception...行的注释,我会得到:

代码语言:javascript
复制
Init outer_object
Init inner_object
Del outer_object
Traceback (most recent call last):
...
Exception: Test exception
Del inner_object

由于异常,inner_object被延迟删除。

如果我取消注释将parameterlocal_variable都设置为None的行,那么我会得到我期望的结果:

代码语言:javascript
复制
Init outer_object
Init inner_object
Del inner_object
Del outer_object
Traceback (most recent call last):
...
Exception: Test exception

那么,当Python中发生异常时,函数局部变量到底会发生什么呢?它们是否被保存在某个地方,这样它们就不会像往常一样超出范围了?控制这种行为的“正确方式”是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-01-13 23:49:28

您的异常处理可能是通过保留对frames的引用来创建引用循环。正如the docs所说:

注意保持对frame对象的引用,如在frame的第一个元素中发现的记录这些函数返回[[NB:“ functions”这里指的是模块中的一些inspect__,但本段的其余部分应用范围更广!]],会导致您的程序创建引用循环。一旦创建了引用周期,即使启用了Python的可选周期检测器,可以从形成周期的对象访问的所有对象的生命周期也会变得更长。如果必须创建这样的循环,重要的是要确保它们被显式打破,以避免延迟销毁对象和增加内存消耗。尽管周期检测器会捕捉到这些,但通过删除finally子句中的周期,可以确定帧(和局部变量)的销毁。如果在编译Python或使用gc.disable()时禁用了周期检测器,这一点也很重要。例如:

代码语言:javascript
复制
def handle_stackframe_without_leak():
    frame = inspect.currentframe()
    try:
        # do something with the frame
    finally:
        del frame
票数 2
EN

Stack Overflow用户

发布于 2010-01-13 17:32:05

函数的作用域是整个函数。在finally中处理此问题。

票数 1
EN

Stack Overflow用户

发布于 2013-02-06 09:27:58

根据this answer for another question的说法,可以通过tb_frame.f_locals进行inspect local variables on the frame in an exception traceback。因此,在异常处理期间,对象看起来确实是“活动的”。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2055611

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档