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

时间:2009-10-25 07:16:18

标签: python string formatting

我在替换字段中使用负索引来输出格式化列表,但它引发了一个TypeError。代码如下:

>>> 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

4 个答案:

答案 0 :(得分:13)

这就是格式字符串规范中我称之为设计故障的内容。每the docs

element_index     ::=  integer | index_string

但是,唉,-1不是“整数” - 它是一个表达式。 unary-minus运算符甚至没有特别高的优先级,因此例如print(-2**2)发出-4 - 另一个常见问题,可以说是设计故障(**运算符具有更高的优先级,因此首先发生上升,然后是较低优先级的一元-所请求的变更符号。

格式字符串中该位置的任何不是整数的东西(例如,表达式)都被视为字符串,以索引dict参数 - 例如:

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

不确定这是否值得在Python trac中提出一个问题,但这肯定是一个有点令人惊讶的行为: - (。

答案 1 :(得分:1)

这里有一些问题,一旦你开始挖掘:

有问题的项目称为“element_index”,它被定义为整数。

问题1:除非用户遵循从“整数”到语言参考手册的链接,否则他们不会知道-1被认为是表达式,而不是整数。顺便说一下,任何试图说“按照文件记录工作”的人都应该首先看到问题7: - )

首选解决方案:更改定义,以便“element_index”在整数之前可以有一个可选的“ - ”。

这是一个整数,对吗?不是那么快......后来文档说“形式'[index]'的表达式使用__getitem__()进行索引查找”

问题3:应该说'[element_index]'(索引未定义)。

问题4:并非所有人都清楚地知道__getitem__()做了什么。需要更清晰的文档。

所以我们可以在这里使用dict以及整数,是吗?是的,有一两个问题:

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被视为str,010(“八进制”)被视为10,而不是8:

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

更新: PEP 3101讲述了真实的故事:
“”“
解析项密钥的规则非常简单。如果以数字开头,则将其视为数字,否则将其用作字符串。

由于键不是以引号分隔的,因此无法在格式字符串中指定任意字典键(例如,字符串“10”或“: - ]”)。
“”“

答案 2 :(得分:1)

正确,它不起作用。溶液:

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

答案 3 :(得分:0)

我经常将Python格式字符串作为配置选项 - 格式字符串与特定的已知关键字参数列表一起提供。因此,在格式字符串中向前或向后寻址可变长度列表的索引正是我最终需要的那种。

我刚刚写了这个黑客来做负面的索引工作:

string_to_tokenise = "Hello_world"
tokens = re.split(r"[^A-Z\d]+", string_to_tokenise, flags=re.I)
token_dict = {str(i) if i < 0 else i: tokens[i] for i in range(-len(tokens) + 1, len(tokens))}
print "{thing[0]} {thing[-1]}".format(thing=token_dict)

结果:

Hello world

因此,为了解释,我创建了一个字典,其中包含所有必需的整数键,用于将列表从0索引到len(..) - 1,而且我还添加了负整数键,而不是传入令牌列表。从结尾的索引从-1到 - (len(..) - 1),但这些键从整数转换为字符串,因为格式将解释它们。