使用十六进制,八进制或二进制整数作为Python的str.format()方法的参数索引时的KeyError

dav*_*ers 5 python string-formatting python-2.7 python-3.3

简单使用Python的str.format()方法:

>>> '{0}'.format('zero')
'zero'
Run Code Online (Sandbox Code Playgroud)

十六进制,八进制和二进制文字不起作用:

>>> '{0x0}'.format('zero')
KeyError: '0x0'
>>> '{0o0}'.format('zero')
KeyError: '0o0'
>>> '{0b0}'.format('zero')
KeyError: '0b0'
Run Code Online (Sandbox Code Playgroud)

根据替换字段语法,他们应该:

replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
arg_name          ::=  [identifier | integer]
attribute_name    ::=  identifier
element_index     ::=  integer | index_string
index_string      ::=  <any source character except "]"> +
conversion        ::=  "r" | "s"
format_spec       ::=  <described in the next section>
Run Code Online (Sandbox Code Playgroud)

整数语法如下:

longinteger    ::=  integer ("l" | "L")
integer        ::=  decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::=  nonzerodigit digit* | "0"
octinteger     ::=  "0" ("o" | "O") octdigit+ | "0" octdigit+
hexinteger     ::=  "0" ("x" | "X") hexdigit+
bininteger     ::=  "0" ("b" | "B") bindigit+
nonzerodigit   ::=  "1"..."9"
octdigit       ::=  "0"..."7"
bindigit       ::=  "0" | "1"
hexdigit       ::=  digit | "a"..."f" | "A"..."F"
Run Code Online (Sandbox Code Playgroud)

我是否误解了文档,或者Python的行为不像宣传的那样?(我使用的是Python 2.7.)

aba*_*ert 4

这看起来像是语法错误。文本中没有任何内容可以澄清这一点;它只是将其描述为“一个数字或一个标识符”,并讨论了如何解释它是一个数字。

\n\n

测试一下,该字段显然不被视为integer

\n\n
>>> \'{08}\'.format(*range(10)) # should be SyntaxError\n\'8\'\n>>> \'{010}\'.format(*range(10)) # should be \'8\'\n\'10\'\n>>> \'{-1}\'.format(*range(10)) # should be \'9\', but looked up as a string\nKeyError: \'-1\'\n>>> \'{1 }\'.format(*range(10)) # should be \'1\', but looked up as a string\nKeyError: \'1 \'\n>>> \'{10000000000000000000}\'.format(1) # should be IndexError\nValueError: Too many decimal digits in format string\n
Run Code Online (Sandbox Code Playgroud)\n\n

看代码,它并没有借用Python解析器来解析格式字符串;它使用自定义解析,将 arg_spec 解释为数字的代码使用一个函数get_integer,该函数仅转换每个数字并移位并添加,直到该字段结束或我们进入 的数字内PY_SSIZE_T_MAX

\n\n

PEP 3101表明这是故意的:

\n\n
\n

简单的字段名称可以是名称或数字。如果是数字,则它们必须是有效的以 10 为基数的整数\xc2\xa0\xe2\x80\xa6

\n
\n\n

它并没有具体说它不能太接近最大索引值,也没有说不能使用负索引。但大多数其他怪癖可以通过使用“有效的以 10 为基数的整数”描述来解释,而不仅仅是“整数”。事实上,只要将其描述为而digit +不是就integer可以解决所有的怪癖。

\n\n

element_index解析方式与 完全相同arg_name#8985有意表示element_index“\xe2\x80\xa6 使用整数索引的最窄定义,以便将所有其他字符串传递给映射。” 我不确定这是否也是有意为之arg_name,或者是否是使用相同代码的意外结果。

\n\n

3.4中的文档没有变化,当前主干中的代码实际上也没有变化。

\n\n

我建议搜索错误跟踪器python-dev档案,看看以前是否曾提出过这个问题。如果没有,请弄清楚您是否认为应该更改文档或代码,提交错误,最好提交补丁。

\n