Декоратор Python с попыткой/за исключением ошибки, не вызывающей

Я экспериментирую с декораторами Python, чтобы понять, что происходит, и я столкнулся с проблемой.

Мой код таков (python 2.7.6):

import traceback
def dec(func):
    def wrapped(*args, **kwargs):
        try:
            if flag:
                print 'flagged'
            else:
                print 'unflagged'
        except NameError as e:
            print 'error?'
            raise
        finally:
            return func(*args, **kwargs)
    return wrapped

@dec
def foo(x):
    print x

foo(3)

при запуске вывод:

error?
3

Я ожидал, что вызов foo(3) вызовет:

NameError: global name 'flag' is not defined

Почему "рейз" не повышается? Ясно, ошибка поймана - выполняется печать из блока Except...


person tom stratton    schedule 19.02.2015    source источник
comment
Кажется, это как-то связано со временем выхода из блока finally — предложение finally всегда выполняется перед выходом из оператора try, независимо от того, произошло исключение или нет. Если в предложении try возникло исключение, которое не было обработано предложением exclude (или оно возникло в предложении exclude или else), оно повторно возникает после выполнения предложения finally. Предложение finally также выполняется «на выходе», когда любое другое предложение оператора try остается с помощью оператора break, continue или return. Не уверен, почему ошибка никогда не возникает   -  person tom stratton    schedule 19.02.2015


Ответы (1)


return в finally переопределяет и отменяет любое исключение или возврат функции, которые могли вызвать блок finally. Это описано в Справочнике по языку Python:

Если присутствует finally, он указывает обработчик «очистки». Предложение try выполняется, включая любые предложения except и else. Если исключение возникает в любом из предложений и не обрабатывается, исключение временно сохраняется. Предложение finally выполняется. Если есть сохраненное исключение, оно повторно вызывается в конце предложения finally. Если предложение finally вызывает другое исключение или выполняет оператор return или break, сохраненное исключение отбрасывается:

Например:

def f():
    try:
        1/0
    finally:
        return

f() # No exception

def g():
    try:
        return 1
    finally:
        return 0

g() # 0

def h():
    try:
        raise NameError
    finally:
        raise TypeError

h() # TypeError
person user2357112 supports Monica    schedule 19.02.2015
comment
Я не дочитал до конца (у меня все равно кружилась голова, пытаясь следовать логике). - person tom stratton; 19.02.2015