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

时间:2013-10-05 22:03:45

标签: python python-2.7 string-formatting python-3.3

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

>>> '{0}'.format('zero')
'zero'

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

>>> '{0x0}'.format('zero')
KeyError: '0x0'
>>> '{0o0}'.format('zero')
KeyError: '0o0'
>>> '{0b0}'.format('zero')
KeyError: '0b0'

根据replacement field grammar,他们应该:

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>

integer grammar如下:

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"

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

1 个答案:

答案 0 :(得分:4)

这看起来像语法中的错误。文本没有什么可澄清的;它只是将其描述为“数字或标识符”,并讨论如何解释数字。

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

>>> '{08}'.format(*range(10)) # should be SyntaxError
'8'
>>> '{010}'.format(*range(10)) # should be '8'
'10'
>>> '{-1}'.format(*range(10)) # should be '9', but looked up as a string
KeyError: '-1'
>>> '{1 }'.format(*range(10)) # should be '1', but looked up as a string
KeyError: '1 '
>>> '{10000000000000000000}'.format(1) # should be IndexError
ValueError: Too many decimal digits in format string

查看代码,它不会从Python解析器借用来解析格式字符串;它使用自定义解析,并且将arg_spec解释为数字的代码使用get_integer函数,该函数仅转换每个数字并移位并添加,直到字段结束或我们得到PY_SSIZE_T_MAX的数字。

PEP 3101表明这是故意的:

  

简单字段名称可以是名称或数字。如果是数字,它们必须是有效的基数为10的整数......

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

element_index的解析方式与arg_name完全相同。 #8985假设element_index故意“...使用最小的整数索引定义,以便将所有其他字符串传递给映射。”这是否也是arg_name的故意,或者是否是使用相同代码的意外后果,我不确定。

文档在3.4中保持不变,代码在current trunk中实际上没有变化。

我建议您搜索bug trackerpython-dev档案,看看之前是否已提出此档案。如果没有,请确定您是否认为应该更改文档或代码,提交错误,并最好提交补丁。