Which is better way to get exception message: str(e) vs e.args[0]?

Viewed 3017

Let's consider a case where I throw built-in Exception with message and when handling it I store exception message. I know I can do it in 2 ways like in an example below.

try:
    raise Exception('some message')
except Exception as e:
    value_str = str(e)
    value_args = e.args[0]

Is there any rationale that one way is better than the other?

1 Answers

Generally, using str(e) would be safer because there are cases where e.args[0] can raise an index error:

try:
    raise Exception()
except Exception as e:
    value = e.args[0]

>>> IndexError: tuple index out of range

There are also cases where the first argument is not actually the message whereas str(e) simply calls e.__str__() which should always return the message.

However, in your specific case using e.args[0] seems to be slightly faster:

import timeit


def test_args():
    try:
        raise Exception('some message')
    except Exception as e:
        value = e.args[0]


def test_str():
    try:
        raise Exception('some message')
    except Exception as e:
        value = str(e)


print(timeit.timeit('test_args()', setup='from __main__ import test_args'))
print(timeit.timeit('test_str()', setup='from __main__ import test_str'))

>>> 0.5408027
>>> 0.5728966000000001

If this minimal increase in execution speed matters and you are certain that e always has at least one argument, go for e.args[0]. When catching specific types of exceptions, you could also consider directly accessing attributes. In all other cases I recommend using str(e).

See the traceback module for more options of retrieving information from your exceptions.

Related