简体   繁体   English

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

[英]str.format(list) with negative index doesn't work in Python

I use a negative index in replacement fields to output a formatted list,but it raises a TypeError.The codes are as follows:我在替换字段中使用负索引输出格式化列表,但它引发了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

It's what I would call a design glitch in the format string specs.这就是我所说的格式字符串规范中的设计故障。 Perthe docs ,根据文档

element_index     ::=  integer | index_string

but, alas, -1 is not "an integer" -- it's an expression.但是,唉, -1不是“整数”——它是一个表达式。 The unary-minus operator doesn't even have particularly high priority, so that for example print(-2**2) emits -4 -- another common issue and arguably a design glitch (the ** operator has higher priority, so the raise-to-power happens first, then the change-sign requested by the lower priority unary - ).一元减号运算符甚至没有特别高的优先级,因此例如print(-2**2)发出-4 - 另一个常见问题,可以说是设计故障( **运算符具有更高的优先级,因此raise-to-power 首先发生,然后是较低优先级的一元请求的更改符号- )。

Anything in that position in the format string that's not an integer (but, for example, an expression) is treated as a string, to index a dict argument -- for example:格式字符串中该位置的任何不是整数(但是,例如,表达式)的任何内容都被视为字符串,以索引 dict 参数 - 例如:

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

Not sure whether this is worth raising an issue in the Python trac, but it's certainly a somewhat surprising behavior:-(.不确定这是否值得在 Python 跟踪中提出问题,但这肯定是一个有点令人惊讶的行为:-(。

There are a few problems here, once you start digging:一旦你开始挖掘,这里有一些问题:

The item in question is called "element_index" which is defined to be an integer.有问题的项目称为“element_index”,它被定义为一个整数。

Problem 1: unless users follow the link from "integer" to the language reference manual, they won't know that -1 is deemed to be an expression, not an integer.问题 1:除非用户点击从“整数”到语言参考手册的链接,否则他们不会知道 -1 被视为表达式,而不是整数。 By the way, anyone tempted to say "works as documented" should see proplem 7 first :-)顺便说一句,任何想说“按文档工作”的人都应该先看看问题 7 :-)

Preferred solution: change the definition so that "element_index" can have an optional '-' before the integer.首选解决方案:更改定义,以便“element_index”可以在整数前有一个可选的“-”。

It's an integer, right?它是一个整数,对吧? Not so fast ... later the docs say that "an expression of the form '[index]' does an index lookup using __getitem__() "没那么快……后来文档说“'[index]' 形式的表达式使用__getitem__()进行索引查找”

Problem 3: Should say '[element_index]' (index is not defined).问题 3:应该说 '[element_index]'(索引未定义)。

Problem 4: Not everybody knows off the top of their heads what __getitem__() does.问题 4:不是每个人都清楚地知道__getitem__()是做什么的。 Needs clearer docs.需要更清晰的文档。

So we can use a dict here as well as an integer, can we?所以我们可以在这里使用字典和整数,对吗? Yes, with a problem or two:是的,有一两个问题:

The element_index is a integer? element_index 是一个整数? Yes, that works with a dict:是的,这适用于字典:

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

It seems that we can also use non-integer strings, but this needs more explicit documentation (Problem 5):似乎我们也可以使用非整数字符串,但这需要更明确的文档(问题 5):

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

But we can't use a dict with a key like '2' (Problem 6):但是我们不能使用带有像“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'"

Problem 7: That "integer" should really be documented to be "decimalinteger" ... 0x22 and 0b11 are treated as str, and 010 (an "octalinteger") is treated as 10, not 8:问题 7:“整数”应该真正记录为“十进制整数”...... 0x22 和 0b11 被视为 str,而 010(“八进制整数”)被视为 10,而不是 8:

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

Update: PEP 3101 tells the true story:更新: PEP 3101讲述了真实的故事:
""" """
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.如果它以数字开头,则将其视为数字,否则将其用作字符串。

Because keys are not quote-delimited, it is not possible to specify arbitrary dictionary keys (eg, the strings "10" or ":-]") from within a format string.因为键不是引号分隔的,所以不可能从格式字符串中指定任意的字典键(例如,字符串“10”或“:-]”)。
""" """

Correct, it does not work.正确,它不起作用。 solution:解决方案:

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

I often take Python format strings as config options - with the format string provided with a specific, known list of keyword arguments.我经常将 Python 格式字符串作为配置选项 - 格式字符串提供了一个特定的、已知的关键字参数列表。 Therefore addressing the indexes of a variable length list forwards or backwards within the format string is exactly the kind of thing I end up needing.因此,在格式字符串中向前或向后处理可变长度列表的索引正是我最终需要的那种东西。

I've just written this hack to make the negative indexing work:我刚刚写了这个 hack 来使负索引工作:

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)

Result:结果:

Hello world

So to explain, instead of passing in the list of tokens, I create a dictionary with all the required integer keys for indexing the list from 0 to len(..)-1, and I also add the negative integer keys for indexing from the end from -1 to -(len(..)-1), however these keys are converted from integers to strings, as that's how format will interpret them.因此,为了解释一下,我没有传入标记列表,而是创建了一个字典,其中包含用于索引从 0 到 len(..)-1 列表的所有必需整数键,并且我还添加了负整数键以从从 -1 到 -(len(..)-1) 结束,但是这些键从整数转换为字符串,因为这就是 format 解释它们的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM