Why does Python log a SyntaxWarning saying “list indices must be integers or slices”?
Take this code, which we want to return a list of two breakfast orders:
def get_orders(): return [ ["egg", "spam"] ["egg", "bacon", "spam"] ]
If we import it in Python 3.8+, we’ll see a warning message on line 3:
>>> import example /.../example.py:3: SyntaxWarning: list indices must be integers or slices, not tuple; perhaps you missed a comma? ["egg", "spam"]
This is a new warning added in Python 3.8. From the release notes:
When a comma is missed in code such as
[(10, 20) (30, 40)], the compiler displays a
SyntaxWarningwith a helpful suggestion. This improves on just having a
TypeErrorindicating that the first tuple was not callable. (Contributed by Serhiy Storchaka in bpo-15248.)
Indeed, if we run the function, it raises a
>>> example.get_orders() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/.../example.py", line 3, in get_orders ["egg", "spam"] TypeError: list indices must be integers or slices, not tuple
Python emits the
SyntaxWarning at import time because it can predict that the code will raise this
TypeError. So why does the error occur?
Some objects in Python are indexable, such as lists. (Indexing is a form of subscripting.) You index a list with the syntax:
some_list[index_or_slice]. This will fetch a single element from the list in
some_list if you use a number as an index, such as
some_list, or a range of elements if you use a slice as the index, such as
Although it is rarely necessary, you can also spread the indexing syntax over multiple lines, for example:
If this happens within parentheses or square brackets, you can also put the square brackets on a new line entirely:
This looks odd, and I don’t think it’s ever necessary in Python code, but it’s valid.
get_orders() function follows this pattern, unintentionally. We could replace
["egg", "spam"], and
["egg", "bacon", "spam"]. So the second line,
["egg", "bacon", "spam"], is not interpreted as a second list, but as an index of the first list. The
index_or_slice in the index is a tuple of three elements, without parentheses:
"egg", "bacon", "spam". Lists only support integers and slices for indexing, so this line raises a
The fix is to follow the
SyntaxWarning and add a comma after the first list:
def get_orders(): return [ ["egg", "spam"], ["egg", "bacon", "spam"], ]
This comma separates the two lists, so our function can return them in the outer list, as intended.
Note there’s now also a comma after the second order list. You should form a habit to always end each item in a multi-line list with a comma, even when it’s the last one. Then you can never encounter the error.
Python raises this
SyntaxWarning for more types than just lists. It also raises them for several indexable built-in types:
- Strings, including f-strings
- Container types -
- List comprehensions
You can see this on the console, for example with an f-string:
>>> def example(): ... return f"123"[1, 2] ... <stdin>:2: SyntaxWarning: str indices must be integers or slices, not tuple; perhaps you missed a comma?
Make your development more pleasant with Boost Your Django DX.
One summary email a week, no spam, I pinky promise.
- Why does Python log a SyntaxWarning for ‘is’ with literals?
- Why does Python log a SyntaxWarning saying “object is not subscriptable”?
- Why does Python log a SyntaxWarning saying “assertion is always true”?
- Why does Python log a SyntaxWarning saying “object is not callable”?