Bad except clauses order¶
When an exception occurs, Python will search for the first exception clause which matches the exception type that occurred. It doesn’t need to be an exact match. If the exception clause represents a base class of the raised exception, then Python considers that exception clause to be a match. E.g. if a ZeroDivisionError
exception is raised and the first exception clause is Exception
, then the Exception
clause will execute because ZeroDivisionError
is a sub class of Exception
. Therefore, more specific exception clauses of sub classes should always be placed before the exception clauses of their base classes to ensure that exception handling is as specific and as helpful as possible.
Anti-pattern¶
The code below performs a division operation that results in a ZeroDivisionError
. The code contains an except clause for this type of error, which would be really useful because it pinpoints the exact cause of the problem. However, the ZeroDivisionError
exception clause is unreachable because there is a Exception
exception clause placed before it. When Python experiences an exception, it will linearly test each exception clause and execute the first clause that matches the raised exception. The match does not need to be identical. So long as the raised exception is a sub class of the exception listed in the exception clause, then Python will execute that clause and will skip all other clauses. This defeats the purpose of exception clauses, which is to identify and handle exceptions with as much precision as possible.
try:
5 / 0
except Exception as e:
print("Exception")
# unreachable code!
except ZeroDivisionError as e:
print("ZeroDivisionError")
Best practice¶
Move sub class exception clause before its ancestor’s clause¶
The modified code below places the ZeroDivisionError
exception clause in front of the Exception
exception clause. Now when the exception is triggered the ZeroDivisionError
exception clause will execute, which is much more optimal because it is more specific.
try:
5 / 0
except ZeroDivisionError as e:
print("ZeroDivisionError")
except Exception as e:
print("Exception")
References¶
Pylint - E0701, bad-except-order