list indices must be integers or slices, not str

Chris Angelico rosuav at gmail.com
Wed Jul 20 07:08:35 EDT 2022


On Wed, 20 Jul 2022 at 20:55, Frank Millman <frank at chagford.com> wrote:
>
> On 2022-07-20 11:37 AM, Chris Angelico wrote:
> > On Wed, 20 Jul 2022 at 18:34, Frank Millman <frank at chagford.com> wrote:
> >>
> >> Hi all
> >>
> >> C:\Users\E7280>python
> >> Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64
> >> bit (AMD64)] on win32
> >> Type "help", "copyright", "credits" or "license" for more information.
> >>   >>>
> >>   >>> x = list(range(10))
> >>   >>>
> >>   >>> '{x[1]}'.format(**vars())
> >> '1'
> >>   >>>
> >>   >>> '{x[-1]}'.format(**vars())
> >> Traceback (most recent call last):
> >>     File "<stdin>", line 1, in <module>
> >> TypeError: list indices must be integers or slices, not str
> >>   >>>
> >>
> >> Can anyone explain this error? It seems that a negative index is deemed
> >> to be a string in this case.
> >>
> >
> > Yeah, that does seem a little odd. What you're seeing is the same as
> > this phenomenon:
> >
> >>>> "{x[1]} {x[spam]}".format(x={1: 42, "spam": "ham"})
> > '42 ham'
> >>>> "{x[1]} {x[spam]}".format(x={"1": 42, "spam": "ham"})
> > Traceback (most recent call last):
> >    File "<stdin>", line 1, in <module>
> > KeyError: 1
> >
> > But I can't find it documented anywhere that digits-only means
> > numeric. The best I can find is:
> >
> > https://docs.python.org/3/library/string.html#formatstrings
> > """The arg_name can be followed by any number of index or attribute
> > expressions. An expression of the form '.name' selects the named
> > attribute using getattr(), while an expression of the form '[index]'
> > does an index lookup using __getitem__()."""
> >
> > and in the corresponding grammar:
> >
> > field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
> > index_string      ::=  <any source character except "]"> +
> >
> > In other words, any sequence of characters counts as an argument, as
> > long as it's not ambiguous. It doesn't seem to say that "all digits is
> > interpreted as an integer, everything else is interpreted as a
> > string". ISTM that a negative number should be interpreted as an
> > integer too, but that might be a backward compatibility break.
> >
>
> Thanks for investigating this further. I agree it seems odd.
>
> As quoted above, an expression of the form '[index]' does an index
> lookup using __getitem()__.
>
> The only __getitem__() that I can find is in the operator module, and
> that handles negative numbers just fine.

In general, __getitem__ is the method used to handle those sorts of lookups:

class X:
    def __getitem__(self, item):
        print("Get item", type(item), item)

"{x[0]} {x[1]} {x[-1]} {x[spam]} {x[1.0]}".format(x=X())

Outside of a format directive, you'd need to quote those:

x[0], x[1], x["spam"]

The distinction is that unquoted bare numbers are interpreted as
integers, not as strings. I'm unable to find the exact definition of
that documented.

> Do you think it is worth me raising an issue, if only to find out the
> rationale if there is one?
>

I'd wait for other people's responses first, there may be a better
insight to be found than what I was able to come across.

ChrisA


More information about the Python-list mailing list