Adam Johnson

Home | Blog | Training | Projects | Colophon | Contact

Why does Python log a SyntaxWarning saying "object is not subscriptable"?

2020-06-17 The snake is out of the box now

Take this code:

flavours = ["chocolate", "cherry", "mango"]


def get_first_flavour():
    return 0[flavours]

If we import its containing module in Python 3.8+, we’ll see a warning message on line 4:

>>> import example
/.../example.py:4: SyntaxWarning: 'int' object is not subscriptable; perhaps you missed a comma?
  return 0[flavours]

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 SyntaxWarning with a helpful suggestion. This improves on just having a TypeError indicating that the first tuple was not callable. (Contributed by Serhiy Storchaka in bpo-15248.)

I covered the described case of a missing comma previously in its own post. The “object is not subscriptable” case is a bit of a bonus for this change, added in the same pull request.

Indeed, if we run the function, it raises a TypeError:

>>> example.get_first_flavour()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../example.py", line 4, in get_first_flavour
    return 0[flavours]
TypeError: 'int' object is not subscriptable

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 subscriptable, such as lists. You normally “subscript” them with the syntax: some_object[index_or_slice]. This will fetch a single element if you use a number as an index, such as some_object[0], or a range of elements if you use a slice, such as some_object[1:3].

Our get_first_flavour() function uses this syntax incorrectly - it has the index and subscriptable object in the wrong positions. We can fix the function by swapping them:

flavours = ["chocolate", "cherry", "mango"]


def get_first_flavour():
    return flavours[0]

Then the function works as expected:

>>> example.get_first_flavour()
'chocolate'

Great.

Missing Commas

The “perhaps you missed a comma?” hint did not apply in the above example. It would apply in other cases, such as function call arguments. For example, if we had this code:

pick_some_flavours(2 ["chocolate", "cherry", "mango"])

We meant to call pick_some_flavours() with two arguments, an int and a list, but the comma between them is missing. If we run this in the console, we see the syntax warning:

>>> def make_cone():
...     flavours = pick_some_flavours(2 ["chocolate", "cherry", "mango"])
...     ...
...
<stdin>:2: SyntaxWarning: 'int' object is not subscriptable; perhaps you missed a comma?

Here, the solution is to insert the comma between the two arguments:

pick_some_flavours(2, ["chocolate", "cherry", "mango"])

Other Types

Python raises this SyntaxWarning for more types than just integers. It also raises them for many built-in literal types:

You can see this on the console, for example with a set:

>>> def example():
...     return {"chocolate", "cherry"}[0]
...
<stdin>:2: SyntaxWarning: 'set' object is not subscriptable; perhaps you missed a comma?

Fin

I hope this helps you understand and fix this error,

—Adam


Are your Django project's tests slow? Read Speed Up Your Django Tests now!


Subscribe via RSS, Twitter, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: python