How to quickly figure out which list is causing the error?

Viewed 111

In a python script, if we have multiple lists in a single expression, for example:

a[1] = b[2] + c[3] + d[4]

OR

a[1] = b[c[d[1]]] # (This case added in EDIT)

Now, one of these lists throws an error IndexError: List Index Out of Range because the index is higher than the list length.

Is there a way to improve this default exception handling using try/except statements such that we can instantly figure out which list caused the problem?

Otherwise, one needs to check each list using a command line debugger. I understand that if an IDE is available, then this feature is probably inbuilt into the IDE.

3 Answers

The easiest way to do this is to artificially split the line over several lines. For example:

b =[1]
c = []
d = [1]

a = b[0] + \
    c[0] + \
    d[0]
Traceback (most recent call last):  
    File "/tmp/foo.py", line 7, in <module>
    c[0] + \
IndexError: list index out of range

another option could be to use inspect module to find the line number that raised the error. This requires you to modify the addition + assignment to use local vars previously defined like bv = b[2] though, or else split it over individual lines as shown.

a = [1, 2, 3]
b = [1] * 3
c = [2] * 3
d = [3] * 5

try:
    a[1] = b[2] + \
           c[3] + \
           d[4]

except IndexError:
    from inspect import trace
    var = trace()[0].code_context[0].split('=', 1)[-1].split('[', 1)[0].lstrip(' +-*')
    print(f'The variable that raised the IndexError was: {var}')

Out:

The variable that raised the IndexError was: c

Interesting fact: the following syntax, which I actually consider good coding practice, actually does not behave how you want for an informative stack trace. I have no idea why, unfortunately.

    a[1] = b[2] \
           + c[3] \
           + d[4]

This exact issue has been addressed and will be available in the python-3.11 interpreter . Reproduced below from the release notes: "When printing tracebacks, the interpreter will now point to the exact expression that caused the error instead of just the line. For example:"

Traceback (most recent call last):
  File "distance.py", line 11, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "distance.py", line 6, in manhattan_distance
    return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                           ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'

References:

Release notes and PEP657

Related