Home > other >  Index out of range with multiple lists on same line
Index out of range with multiple lists on same line

Time:10-16

Given

>>> foo = [1, 1]
>>> bar = [1, 1, 1]
>>> print(foo[5], bar[5])

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

How can I tell which list threw the exception?

For more non-trivial examples, this is very irritating. Can someone explain how the Python interpreter works so that it can't remember the character it is on? This seems like too obvious of a design error, so there must be a reason for it, right?

CodePudding user response:

The short answer is you can force it by splitting your print statement across multiple lines (though I agree it is more a workaround than a real solution):

foo = [1, 1]
bar = [2, 2]
print(
    foo[5],
    bar[5]
)

Should result in something like:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    foo[5],
IndexError: list index out of range

Note as well that the dis module might be of help here if one wanted to actually inspect the byte code to see what was happening:

import dis

code_block ='''
foo = [1, 1]
bar = [2, 2]
print(foo[5], bar[5])
'''

print(dis.dis(compile(code_block, "", "exec")))
Tells me:

  2           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               0 (1)
              4 BUILD_LIST               2
              6 STORE_NAME               0 (foo)

  3           8 LOAD_CONST               1 (2)
             10 LOAD_CONST               1 (2)
             12 BUILD_LIST               2
             14 STORE_NAME               1 (bar)

  4          16 LOAD_NAME                2 (print)
             18 LOAD_NAME                0 (foo)
             20 LOAD_CONST               2 (5)
             22 BINARY_SUBSCR
             24 LOAD_NAME                1 (bar)
             26 LOAD_CONST               2 (5)
             28 BINARY_SUBSCR
             30 CALL_FUNCTION            2
             32 POP_TOP
             34 LOAD_CONST               3 (None)
             36 RETURN_VALUE
None

So, on my platform foo[5] is evaluated (via BINARY_SUBSCR) prior to bar.

CodePudding user response:

JonSG's answer will work for all versions of Python. In the future however, Python 3.11 will store column offsets in its bytecode. The traceback will underline the expression that errored:

Traceback (most recent call last):
  File "C:\Users\username\Documents\module.py", line 3, in <module>
    print(foo[5], bar[5])
          ~~~^^^
IndexError: list index out of range

This is thanks to PEP 657 implemented in Python 3.11, currently in alpha, and set to release in October 2022.

Note that this feature carries with it a small memory cost, and the authors have acknowledged that, saying:

We understand that the extra cost of this information may not be acceptable for some users, so we propose an opt-out mechanism which will cause generated code objects to not have the extra information while also allowing pyc files to not include the extra information.

One can opt-out of this feature by passing -Xno_debug_ranges to python.

  • Related