Область видимости локальной переменной функции Python во время исключений - PullRequest
3 голосов
/ 13 января 2010

Справочная информация: я занимаюсь программированием COM в TestStand от National Instruments на Python. TestStand жалуется, если объекты не были «освобождены» должным образом (он вызывает диалоговое окно отладки «объекты не были освобождены должным образом») Способ высвобождения COM-объектов TestStand в Python состоит в том, чтобы все переменные больше не содержали объект, например del() их или установите для них None. Или, если переменные являются локальными переменными функции, объект освобождается, как только переменная выходит из области видимости после завершения функции.

Что ж, я следовал этому правилу в моей программе, и моя программа освобождает объект должным образом, пока нет исключений. Но если я получаю исключение, то получаю сообщение «Объекты не освобождены» из TestStand. Похоже, это указывает на то, что локальные переменные функции не выходят за рамки обычного, когда происходит исключение.

Вот пример упрощенного кода:

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

Когда это работает, как показано, это показывает, что я ожидаю:

Init outer_object
Init inner_object
Del inner_object
Del outer_object

Но если я раскомментирую строку raise Exception..., я получу:

Init outer_object
Init inner_object
Del outer_object
Traceback (most recent call last):
...
Exception: Test exception
Del inner_object

inner_object удаляется поздно из-за исключения.

Если я раскомментирую строки, которые устанавливают parameter и local_variable на None, я получаю то, что ожидаю:

Init outer_object
Init inner_object
Del inner_object
Del outer_object
Traceback (most recent call last):
...
Exception: Test exception

Итак, когда в Python происходят исключения, что именно происходит с локальными переменными функции? Их где-то спасают, чтобы они не выходили за рамки обычного? Что такое «правильный способ» контролировать это поведение?

Ответы [ 3 ]

2 голосов
/ 13 января 2010

Ваша обработка исключений, вероятно, создает циклы ссылок, сохраняя ссылки на фреймы. Как документы выразились:

Примечание Сохранение ссылок на фрейм объекты, найденные в первом элементе кадра записывает эти функции return [[NB: "эти функции" здесь относятся к некоторые в модуле inspect, а остальные абзац применяется более широко!]] , может привести к тому, что ваша программа создать справочные циклы. Когда эталонный цикл был создан, продолжительность жизни всех объектов, которые могут быть доступ из объектов, которые образуют цикл может стать намного длиннее даже если дополнительный детектор цикла Python включен. Если такие циклы должны быть создано, важно обеспечить они явно разбиты, чтобы избежать отсроченное разрушение объектов и увеличенное потребление памяти, которое происходит. Хотя детектор цикла будет поймать это, разрушение кадров (и локальные переменные) могут быть сделаны детерминированный путем удаления цикла в finally пункт. Это тоже важно, если детектор цикла был отключено при компиляции Python или используя gc.disable(). Например:

def handle_stackframe_without_leak():
    frame = inspect.currentframe()
    try:
        # do something with the frame
    finally:
        del frame
1 голос
/ 13 января 2010

Область действия функции для всей функции. Обработайте это в finally.

0 голосов
/ 06 февраля 2013

Согласно этому ответу на другой вопрос , можно проверять локальные переменные в кадре в трассировке исключения через tb_frame.f_locals. Таким образом, все выглядит так, как будто объекты остаются «живыми» на время обработки исключений.

...