在Python中,负索引的str.format(list)不起作用

12 投票
5 回答
2503 浏览
提问于 2025-04-15 15:21

我在替换字段中使用了负数索引来输出一个格式化的列表,但这引发了一个类型错误。代码如下:

>>> a=[1,2,3]
>>> a[2]
3
>>> a[-1]
3
>>> 'The last:{0[2]}'.format(a)
'The last:3'
>>> 'The last:{0[-1]}'.format(a)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: list indices must be integers, not str

5 个回答

1

没错,这个方法不行。解决办法是:

>>> 'The last:{0}'.format(a[-1])
'The last:3'
4

这里有几个问题,一旦你开始深入了解,就会发现:

我们讨论的这个东西叫做“element_index”,它被定义为一个整数。

问题1:除非用户点击“整数”的链接去查看语言参考手册,否则他们不会知道-1被认为是一个表达式,而不是一个整数。顺便说一下,任何想说“按文档说明工作”的人,最好先看看问题7 :-)

推荐的解决方案:改变定义,让“element_index”可以在整数前面加一个可选的'-'。

它是一个整数,对吧?别急……后面的文档说“形如'[index]'的表达式会使用 __getitem__() 进行索引查找。”

问题3:应该说'[element_index]'(index没有定义)。

问题4:并不是每个人都知道 __getitem__() 是干什么的。文档需要更清晰。

所以我们可以在这里使用字典和整数,对吧?是的,但也有一两个问题:

element_index是一个整数?是的,这在字典中是可以的:

>>> "{0[2]}".format({2: 'int2'})
'int2'

看来我们也可以使用非整数的字符串,但这需要更明确的文档(问题5):

>>> "{0[foo]}".format({'foo': 'bar'})
'bar'

但是我们不能用像'2'这样的键来使用字典(问题6):

>>> "{0[2]}".format({'2': 'str2'})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 2
>>> "{0['2']}".format({'2': 'str2'})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: "'2'"

问题7:那个“整数”其实应该记录为“十进制整数”……0x22和0b11被当作字符串处理,而010(一个“八进制整数”)被当作10,而不是8:

>>> "{0[010]}".format('0123456789abcdef')
'a'

更新: PEP 3101 讲述了真实的故事:
"""
解析项键的规则非常简单。如果它以数字开头,那么它被视为数字,否则它被当作字符串使用。

因为键没有用引号括起来,所以无法在格式字符串中指定任意字典键(例如,字符串“10”或“:-]”)。
"""

16

我觉得这在格式字符串的规范中算是一个设计上的小问题。根据文档

element_index     ::=  integer | index_string

但是,遗憾的是,-1并不是“一个整数”——它其实是一个表达式。单目负号的优先级并不高,所以比如说,print(-2**2)会输出-4——这也是一个常见的问题,可以说是设计上的小缺陷(因为**这个运算符的优先级更高,所以先进行幂运算,然后再进行负号的操作)。

在格式字符串中,如果这个位置的内容不是整数(比如说是一个表达式),它会被当作字符串来处理,用来索引一个字典参数——例如:

$ python3 -c "print('The last:{0[2+2]}'.format({'2+2': 23}))"
The last:23

我不确定这是否值得在Python的跟踪系统中提出问题,但这确实是一个有点让人意外的行为:-(。

撰写回答