Better to 'try' something and catch the exception or test if it's possible first to avoid an exception?

exception, if-statement, pep, python, try-catch

Solution

You should prefer `try/except` over `if/else` if that results in

- speed-ups (for example by preventing extra lookups)

- cleaner code (fewer lines/easier to read)

Often, these go hand-in-hand.

speed-ups

In the case of trying to find an element in a long list by:

try:
    x = my_list[index]
except IndexError:
    x = 'NO_ABC'

the try, except is the best option when the `index` is probably in the list and the IndexError is usually not raised. This way you avoid the need for an extra lookup by `if index < len(my_list)`.

Python encourages the use of exceptions, which you handle is a phrase from Dive Into Python. Your example not only handles the exception (gracefully), rather than letting it silently pass, also the exception occurs only in the exceptional case of index not being found (hence the word exception!).

cleaner code

The official Python Documentation mentions EAFP: Easier to ask for forgiveness than permission and Rob Knight notes that catching errors rather than avoiding them, can result in cleaner, easier to read code. His example says it like this:

Worse (LBYL 'look before you leap'):

#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit():
    return None
elif len(s) > 10:    #too many digits for int conversion
    return None
else:
    return int(s)

Better (EAFP: Easier to ask for forgiveness than permission):

try:
    return int(s)
except (TypeError, ValueError, OverflowError): #int conversion failed
    return None

Problem

Should I test `if` something is valid or just `try` to do it and catch the exception? - Is there any solid documentation saying that one way is preferred? - Is one way more pythonic? For example, should I: ``` if len(my_list) >= 4: x = my_list[3] else: x = 'NO_ABC' ``` Or: ``` try: x = my_list[3] except IndexError: x = 'NO_ABC' ``` Some thoughts... PEP 20 says: Errors should never pass silently. Unless explicitly silenced. Should using a `try` instead of an `if` be interpreted as an error passing silently? And if so, are you explicitly silencing it by using it in this way, therefore making it OK? I'm not referring to situations where you can only do things 1 way; for example: ``` try: import foo except ImportError: import baz ```

Original source

Related problems