Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python using exceptions for control flow considered bad?

All right,

I've seen this multiple times in the past, but most recently with my question here. So, I'm curious why this is the case, in python because generators use exceptions to indicate the end of the data.

If this is so bad for everyone using python, why does the language include it in what are considered fundamental control structures? For those who want to read the relevant PEP go here.

like image 778
Spencer Rathbun Avatar asked Sep 01 '11 17:09

Spencer Rathbun


People also ask

Why should exceptions not be used as an alternate form of program control?

Exceptions should rarely be used because exceptional situations are rare and exceptions are expensive. Rare, because you don't expect your program crash at every button press or at every malformed user input.

What is exception explain exception as control flow mechanism with suitable example in Python?

An exception is a signal that a condition has occurred that can't be easily handled using the normal flow-of-control of a Python program. Exceptions are often defined as being “errors” but this is not always the case. All errors in Python are dealt with using exceptions, but not all exceptions are errors.

Are exceptions an anti pattern?

According to many references like here and here, using Exceptions to control application flow is an anti-pattern that is not recommended. (Because of performance issues, Less readable and etc).

Should you use exceptions?

Exceptions should only be used in exceptional circumstances and therefore should be used sparingly. For example, it is correct to use an exception when you are attempting to access the Twitter API and do some processing because if this fails it is an exceptional circumstance.


2 Answers

Because ending the generator is not a common event (I know it will always happen, but it only happens once). Throwing the exception is considered expensive. If an event is going to succeed 99% of the time and fail 1%, using try/except can be much faster than checking if it's okay to access that data (it's easier to ask forgiveness than permission).

There's also a bias against it since try/except blocks used like that can be very difficult to understand. The flow control can be difficult to follow, while an if/else are more straightforward. The try/except means you have to track the flow control of the statements inside the try and inside of the functions it calls (as they may throw the exception and it may propagate upwards. An if/else can only branch at the point when the statement is evaluated.

There are times when using try/except is correct and times when if/else make more sense. There are also performance costs associated with each of them. Consider:

a = <some dictionary>
if key in a:
    print a[key]

vs.

a = <some dictionary>
try:
    print a[key]
except KeyError:
    pass

The first will be faster if key does not exist inside of a and will only be slightly (almost unnoticeable) slower if it does exist. The second will be faster if the key does exist, but will be much slower if it doesn't exist. If key almost always exists, you go with the second. Otherwise, the first works better.

EDIT: Just a little thing to add about Python try/except that helps greatly with one of the readability problems.

Consider reading from a file.

f = None
try:
    f = open(filename, 'r')
    ... do stuff to the file ...
except (IOError, OSError):
    # I can never remember which one of these Python throws...
    ... handle exception ...
finally:
    if f:
        f.close()

Now anything in the do stuff to the file can throw an exception and we'll catch it. Commonly, you try to keep as little code as possible in the try for this reason. Python has an optional else clause for the try that will only be run if the try ran to completion without hitting an exception.

f = None
try:
    f = open(filename, 'r')
except (IOError, OSError):
    pass
else:
    ... do stuff to the file ...
finally:
    if f:
        f.close()

In this case, you would not have any of the readability problems since only one statement is in the try; it is a python standard library function call and you're catching only specific exceptions.

like image 183
Jonathan Sternberg Avatar answered Sep 21 '22 05:09

Jonathan Sternberg


Because exceptions are raised up the stack, they are appropriate for some cases where you want code that uses other code to be able to catch the exception. For example, consider the case where you want to create an iterator that uses part of another iterator more "manually", it's valuable to have an exception you can catch from higher up the stack and insert your own logic.

like image 43
Ross Patterson Avatar answered Sep 20 '22 05:09

Ross Patterson