tom stratton
tom stratton

Reputation: 678

Python Decorator With Try/Except Not Raising Error

I am experimenting with Python Decorators in order to understand what it happening and I have hit a head-scratcher.

My code is this (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)

when run, the output is:

error?
3

I expected that calling foo(3) would raise:

NameError: global name 'flag' is not defined

Why is the "raise" not raising? Clearly, the error is caught - the print from the Except block is executed...

Upvotes: 2

Views: 1442

Answers (1)

user2357112
user2357112

Reputation: 280898

The return in the finally overrides and cancels any exception or function return that might have triggered the finally block. This is documented in the Python Language Reference:

If finally is present, it specifies a ‘cleanup’ handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception, it is re-raised at the end of the finally clause. If the finally clause raises another exception or executes a return or break statement, the saved exception is discarded:

For example:

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

Upvotes: 1

Related Questions