Python: fix SyntaxWarning: 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 aSyntaxWarningwith a helpful suggestion. This improves on just having aTypeErrorindicating that the first tuple was not callable. (Contributed by Serhiy Storchaka in bpo-15248.)
Indeed, if we run the function, it raises a TypeError:
>>> 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[0], or a range of elements if you use a slice as the index, such as some_list[1:3].
Although it is rarely necessary, you can also spread the indexing syntax over multiple lines, for example:
some_list[index_or_slice]
If this happens within parentheses or square brackets, you can also put the square brackets on a new line entirely:
(some_list[index_or_slice])
This looks odd, and I don’t think it’s ever necessary in Python code, but it’s valid.
Our get_orders() function follows this pattern, unintentionally. We could replace some_list with ["egg", "spam"], and [index_or_slice] with ["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 TypeError.
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.
Other Types
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 -
tuple,list - 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?
😸😸😸 Check out my new book on using GitHub effectively, Boost Your GitHub DX! 😸😸😸
One summary email a week, no spam, I pinky promise.
Related posts:
- Python: fix
SyntaxWarning: "is" with a literal - Python: fix
SyntaxWarning: '<type>' object is not subscriptable - Python: fix
SyntaxWarning: assertion is always true - Python: fix
SyntaxWarning: '<type>' object is not callable
Tags: python