Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Error Handling: finally vs. new line dedented

When using try and except for error handling, does it matter whether you explicitly call finally or if you simply go to a new line that is dedented from the exception code? For example, is there any circumstance under which the two functions below will produce different results?

#Function 1 with finally
def final(x):
    try:
        print(x*x)

    except:
        print("Error")

    finally:
        print("End Function")


#Function 2 with new line dedent
def dedent(x):
    try:
        print(x*x)

    except:
        print("Error")

    print("End Function")

Update: Thanks for the explanation of finally running even if there is an error in the except block. One additional thing I wanted to point out is that the finally block will run even if you return an object within the except block. For example, function 3 below will print even after the return while function 4 will not.

#Function 3 with finally
def final(x):
    try:
        print(x*x)

    except:
        return 3

    finally:
        print("End Function 3")


#Function 4 with new line dedent
def dedent(x):
    try:
        print(x*x)

    except:
        return 3

    print("End Function 4")

test1 = final('test')
test2 = dedent('test')
like image 916
Michael Avatar asked Mar 17 '26 01:03

Michael


2 Answers

There is the error in the except block that's been mentioned already:

def final(x):
    try:
        print(x*x)

    except:
        print("Error")
        damnit

    finally:
        print("End Function")

def dedent(x):
    try:
        print(x*x)

    except:
        print("Error")
        damnit

    print("End Function")

try:
    final("a")
except Exception as e:
    print("There was an error:", e)
#>>> Error
#>>> End Function
#>>> There was an error: global name 'damnit' is not defined

try:
    dedent("a")
except Exception as e:
    print("There was an error:", e)
#>>> Error
#>>> There was an error: global name 'damnit' is not defined

There's also return behaviour:

def final(x):
    try:
        print(x*x)

    except:
        print("Error")
        return "Return inside"

    finally:
        print("End Function")
        return "Return outside"

def dedent(x):
    try:
        print(x*x)

    except:
        print("Error")
        return "Return inside"

    print("End Function")
    return "Return outside"

try:
    final("a")
except Exception as e:
    print("There was an error:", e)
#>>> Error
#>>> End Function
#>>> 'Return outside'

try:
    dedent("a")
except Exception as e:
    print("There was an error:", e)
#>>> Error
#>>> 'Return inside'
like image 148
Veedrac Avatar answered Mar 20 '26 11:03

Veedrac


According to PEP 341:

try:
    block-1 ...
except Exception1:
    handler-1 ...
except Exception2:
    handler-2 ...
else:
    else-block
finally:
    final-block

The code in block-1 is executed. If the code raises an exception, the various except blocks are tested: if the exception is of class Exception1, handler-1 is executed; otherwise if it's of class Exception2, handler-2 is executed, and so forth. If no exception is raised, the else-block is executed.

No matter what happened previously, the final-block is executed once the code block is complete and any raised exceptions handled. Even if there's an error in an exception handler or the else-block and a new exception is raised, the code in the final-block is still run.

So as Martjin said, the code in finally will be executed even if the except raises another another error.

like image 33
Nacib Neme Avatar answered Mar 20 '26 12:03

Nacib Neme



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!