Подтвердить что ты не робот

Исключение Python 3 удаляет переменную в закрывающей области по неизвестной причине

У меня есть следующий код:

def foo():
    e = None
    try:
        raise Exception('I wish you would except me for who I am.')
    except Exception as e:
        print(e)
    print(e)

foo()

В Python 2.7 это выполняется как ожидалось и печатает:

I wish you would except me for who I am.
I wish you would except me for who I am.

Однако в Python 3.x печатается первая строка, а вторая - нет. Кажется, что она удаляет переменную в охватывающей области, предоставляя мне следующую трассировку из последнего оператора печати:

Traceback (most recent call last):
  File "python", line 9, in <module>
  File "python", line 7, in foo
UnboundLocalError: local variable 'e' referenced before assignment

Это почти как если инструкция del e вставляется после блока except. Есть ли какие-либо аргументы в пользу такого поведения? Я мог бы это понять, если разработчики Python хотели, чтобы блоки имели свою собственную локальную область, а не течь в окружающую область, но почему она должна удалять переменную во внешней области, которая ранее была назначена?

4b9b3361

Ответ 1

Цитирование документации try,

Когда исключение назначено с помощью as target, оно очищается в конце предложения except. Это как если бы

except E as N:
   foo

был переведен на

except E as N:
    try:
        foo
    finally:
        del N

Это означает, что исключение должно быть назначено другому имени, чтобы иметь возможность ссылаться на него после предложения except. Исключения очищаются, потому что с привязкой к ним трассировки они образуют опорный цикл с фреймом стека, сохраняя все локали в этом фрейме до тех пор, пока не произойдет следующая сборка мусора.

Это описано в этих двух PEP.