Python Forum

Full Version: Am I a retard - else and finally blocks in a try statement
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Came across this gem today:

def reciprocal(n):
    try:
        n = 1 / n
    except ZeroDivisionError:
        print("Division failed")
        n = None
    else:
        print("Everything went fine")
    finally:
        print("It's time to say goodbye")
        return n

print(reciprocal(2))
print(reciprocal(0))
This made is tidier, but can't the content of the else block go into the try block and the finally block outside the try statement entirely - as below:

def reciprocal(n):
    try:
        n = 1 / n
        print("Everything went fine")
    except ZeroDivisionError:
        print("Division failed")
        n = None
    
    print("It's time to say goodbye")
    return n
Do they else and finally blocks serve a better purpose then then a "cleaner" statement?
Although this will work in this case and in general case - for the else part (I will come to back later) there are cases where you definitely will need the finally block and your code will be better using else.

the else part - generally the try block should have as little code as possible, i.e. the code that can cause he error you handle in the except part. Again, in this simple example it doesn't matter, but in more complex code it will make huge difference.

the finally - there are cases, that even if you hit error and normal execution flow is interrupted you want to make sure certain tear-down/clean up code is executed, e.g. you may want write something to disk or close connection to a database, etc. That is where finally comes in play - you know that it will be executed even in case of error.
In the second snippet you never call reciprical.
Add that and you're fine

def reciprocal(n):
    try:
        n = 1 / n
        print("Everything went fine")
    except ZeroDivisionError:
        print("Division failed")
        n = None
     
    print("It's time to say goodbye")
    return n


print(reciprocal(2))
print(reciprocal(0))
Output:
Everything went fine It's time to say goodbye 0.5 Division failed It's time to say goodbye None
Buran, sorry I posted at same time
(Jan-12-2021, 04:01 PM)Larz60+ Wrote: [ -> ]Buran, sorry I posted at same time
@Larz60+, really don't know what you apologize for... :-)
Is having code in the "else" block any better than code in the "try" block? Is it because doing so places a harder focus on what code is expected to raise an exception?
try:
    dangerous code
    innocuous code
except:
    handler code

#vs

try:
    dangerous code
except:
    handler code
else:
    innocuous code
The upper example has the benefit of keeping the code together instead of splitting into little pieces. The bottom example has the benefit of pointing out what code is handled by the exception.

Does finally predate context managers? I can see using finally to close a file or do some other cleanup that is not done by other tools. I can see that it eliminates the need for duplicate code in the except and else blocks, but did it have a more important role?
You label the code "innocuous", but it's hard to guarantee that. In the first case if the innocuous code does raise an exception, it might (incorrectly) be caught by the exception handlers. Putting it in else guarantees that any exceptions it does raise are not caught locally.