list indices must be integers or slices, not str

MRAB python at mrabarnett.plus.com
Wed Jul 20 10:21:23 EDT 2022


On 20/07/2022 12:08, Chris Angelico wrote:
> 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.
> 
It's mentioned in PEP 3101 (Advanced String Formatting):

"""
The rules for parsing an item key are very simple. If it starts with a 
digit, then it is treated as a number, otherwise it is used as a string.
"""

I have a vague memory of it being discussed on python-dev, but it was a 
long time ago.


More information about the Python-list mailing list