On 20/07/2022 12:08, Chris Angelico wrote:
On Wed, 20 Jul 2022 at 20:55, Frank Millman <fr...@chagford.com> wrote:

On 2022-07-20 11:37 AM, Chris Angelico wrote:
> On Wed, 20 Jul 2022 at 18:34, Frank Millman <fr...@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.
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to