1
%%time
for i in range(10000000):
  try:
    x = (type.__abstractmethods__)
  except:
    y, z = 1, 2
CPU times: user 3.59 s, sys: 0 ns, total: 3.59 s
Wall time: 3.6 s
%%time
for i in range(10000000):
  try:
    x = (type.__abstractmethods__)
  except AttributeError as e:
    y, z = 1, 2    
CPU times: user 5.74 s, sys: 0 ns, total: 5.74 s
Wall time: 5.86 s

on one more example,

%%time
for i in range(10000000):
  try:
    print(1/0)
  except:
    y, z = 1, 2
CPU times: user 4.22 s, sys: 1.72 ms, total: 4.22 s
Wall time: 4.23 s
%%time
for i in range(10000000):
  try:
    print(1/0)
  except ZeroDivisionError:
    y, z = 1, 2
CPU times: user 5.14 s, sys: 4.88 ms, total: 5.14 s
Wall time: 5.16 s

clearly not specifying the exception type gives an improvement in time, then why would I ever want to specify the exception type (assume I am not using the exception type in the except block)?

apostofes
  • 2,959
  • 5
  • 16
  • 31
  • 1
    I challenge the benchmark. Did you run that multiple times, or just once and assume the result was good? Because both of those do the exact same amount of work. Even if you don't specify a type for the exception, you still check against `Exception` (there are exceptions such as `StopIteration` that do not derive from that class). So I contend that the 2-second difference is pure noise and not a meaningful result. – Silvio Mayolo Apr 17 '22 at 01:13
  • 1
    One reason to specify the exception type is if you wanted to have multiple `except` clauses to catch different exceptions. – Nick Apr 17 '22 at 01:14
  • 1
    Note that the behaviour of the code is different too; in the second case if your code doesn't raise an `AttributeError` then the exception will be passed to any outer `try/except` blocks; if there are none then an unhandled exception error will occur. – Nick Apr 17 '22 at 01:15
  • 1
    https://docs.python.org/3/tutorial/errors.html#handling-exceptions – Nick Apr 17 '22 at 01:16
  • 1
    See also https://stackoverflow.com/questions/10594113/bad-idea-to-catch-all-exceptions-in-python; in brief, a blanket `except` is basically nearly always a bug, as it will prevent Python from reporting actually useful exceptions. – tripleee Apr 17 '22 at 11:44
  • @apostofes Does my answer answer your question? – OTheDev Apr 17 '22 at 21:32

1 Answers1

1

Consider Snippet 1 and 2 and the associated timings (below). The reason Snippet 2 is slower is because Snippet 1 has an expression-less except clause whereas Snippet 2's except clause does have an expression. If an except clause has an expression, it needs to be evaluated and tested against the raised exception. An expression-less except clause does not have to do this additional step. From the documentation:

An expression-less except clause, if present, must be last; it matches any exception. For an except clause with an expression, that expression is evaluated, and the clause matches the exception if the resulting object is “compatible” with the exception.

In Snippet 1, when an AttributeError is raised, the only except clause is this expression-less except clause which matches any exception and so it is entered immediately. In Snippet 2, when an AttributeError is raised, the only except clause is one with the expression AttributeError. The expression after the except, AttributeError, has to be evaluated and tested against the raised exception. This does not happen in Snippet 1. Consequently, Snippet 1 will be faster than Snippet 2.

why would I ever want to specify the exception type (assume I am not using the exception type in the except block)?

The try suite (the block of code under the try) may raise different types of exceptions. Depending on the type of exception, you may want to handle it differently. If you specify an expression-less except clause, if that except clause is reached, it will be entered regardless of the type of the exception.

If you know you want to handle every exception the same way, you can choose not to specify exception types. Some try to handle any exception by using except BaseException (or handle a subset of these exceptions using except Exception), but specifying BaseException and Exception yields virtually identical timings to Snippet 2 below (see, for example, Snippet 3) for the simple reason that BaseException and Exception also need to be evaluated and tested against the raised exception.

Here is a toy example that prints a different message to the user depending on the type of the exception that was raised.

while True:
    try:
        x = int(input("Enter x: "))
        y = int(input("Enter y: "))
        z = x / y
        
    except ZeroDivisionError:
        print("Undefined. Zero division error.")
        continue

    except ValueError:
        print("Please enter an integer!")
        continue

    print(f"x / y = {z}")
    break

Snippet 1

try:
    # generates AttributeError
    x = type.__abstractmethods__
except:
    y, z = 1, 2 

Snippet 2

try:
    # generates AttributeError
    x = type.__abstractmethods__
except AttributeError:
    y, z = 1, 2 

Snippet 3 (bonus)

try:
    # generates AttributeError
    x = type.__abstractmethods__
except BaseException:
    y, z = 1, 2 

Timings

# snippet 1
221 ns ± 0.782 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)
# snippet 2
242 ns ± 0.905 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)
# snippet 3 
241 ns ± 1.23 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)
OTheDev
  • 2,916
  • 2
  • 4
  • 20
  • that is what confuses me, if I do not want to use the exception type in the except block, then there is no reason for me to specify it, as it only increases the time, but IDE like PyCharm would give a warning 'Unclear exception clauses' if you do not specify the exception type – apostofes Apr 17 '22 at 22:05
  • 1
    Sure, you do not need to specify it though I personally wouldn't recommend handling all exceptions in one place, unless they really all do only need a homogeneous solution. You can find a way to suppress the warning from PyCharm. I don't use it but try placing `# noinspection PyBroadException` just above the `try` clause. @apostofes – OTheDev Apr 17 '22 at 22:11
  • @apostofes If my answer is helpful at all, please consider upvoting and/or accepting the answer by clicking the check-mark. This is completely optional of course and no love would be lost if you do not. – OTheDev Apr 17 '22 at 22:28