为什么 Python 3 允许“00"?作为 0 的文字,但不允许使用“01";作为 1 的文字?

问题描述

为什么 Python 3 允许00"作为 0 的文字,但不允许01"作为 1 的文字?有充分的理由吗?这种不一致让我感到困惑.(我们谈论的是 Python 3,它故意破坏向后兼容性以实现一致性等目标.)

Why does Python 3 allow "00" as a literal for 0 but not allow "01" as a literal for 1? Is there a good reason? This inconsistency baffles me. (And we're talking about Python 3, which purposely broke backward compatibility in order to achieve goals like consistency.)

例如:

>>> from datetime import time
>>> time(16, 00)
datetime.time(16, 0)
>>> time(16, 01)
  File "<stdin>", line 1
    time(16, 01)
              ^
SyntaxError: invalid token
>>>


解决方案

根据 https://docs.python.org/3/reference/lexical_analysis.html#integer-literals:

整数字面量由以下词法定义描述:

Integer literals are described by the following lexical definitions:

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

整数文字的长度没有限制,除了可以存储在可用内存中.

There is no limit for the length of integer literals apart from what can be stored in available memory.

请注意,不允许在非零十进制数中使用前导零.这是为了消除 C 风格的八进制文字的歧义,Python在 3.0 之前使用.

Note that leading zeros in a non-zero decimal number are not allowed. This is for disambiguation with C-style octal literals, which Python used before version 3.0.

如此处所述,非零十进制数中的前导零是不允许的."0"+ 作为一个非常特殊的情况是合法的,它 在 Python 2 中不存在:

As noted here, leading zeros in a non-zero decimal number are not allowed. "0"+ is legal as a very special case, which wasn't present in Python 2:

integer        ::=  decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::=  nonzerodigit digit* | "0"
octinteger     ::=  "0" ("o" | "O") octdigit+ | "0" octdigit+

<小时>

SVN commit r55866 实现了 PEP3127 在标记器中,它禁止旧的 0 数字.然而,奇怪的是,它还添加了这个注释:


SVN commit r55866 implemented PEP 3127 in the tokenizer, which forbids the old 0<octal> numbers. However, curiously, it also adds this note:

/* in any case, allow '0' as a literal */

带有一个特殊的 nonzero 标志,仅当以下数字序列包含非零数字时才抛出 SyntaxError.

with a special nonzero flag that only throws a SyntaxError if the following sequence of digits contains a nonzero digit.

这很奇怪,因为 PEP 3127 不允许这种情况:

This is odd because PEP 3127 does not allow this case:

此 PEP 提议将在 Python 3.0(以及 2.6 的 Python 3.0 预览模式)中删除使用前导零指定八进制数的功能,并且将在任何时候引发 SyntaxError前导0"后紧跟另一个数字.

This PEP proposes that the ability to specify an octal number by using a leading zero will be removed from the language in Python 3.0 (and the Python 3.0 preview mode of 2.6), and that a SyntaxError will be raised whenever a leading "0" is immediately followed by another digit.

(强调我的)

因此,允许多个零的事实在技术上违反了 PEP,并且基本上是由 Georg Brandl 作为特例实现的.他对文档进行了相应的更改,指出 "0"+decimalinteger 的有效案例(之前已在 octinteger 中介绍过).

So, the fact that multiple zeros are allowed is technically violating the PEP, and was basically implemented as a special case by Georg Brandl. He made the corresponding documentation change to note that "0"+ was a valid case for decimalinteger (previously that had been covered under octinteger).

我们可能永远不会确切地知道为什么 Georg 选择使 "0"+ 有效 - 它可能永远是 Python 中一个奇怪的极端情况.

We'll probably never know exactly why Georg chose to make "0"+ valid - it may forever remain an odd corner case in Python.

更新 [2015 年 7 月 28 日]:这个问题导致了 关于 python-ideas 的热烈讨论帖 其中 Georg 插话:

UPDATE [28 Jul 2015]: This question led to a lively discussion thread on python-ideas in which Georg chimed in:

史蒂文·达普拉诺写道:

Steven D'Aprano wrote:

为什么要这样定义?[...] 为什么我们要写 0000 来得到零?

Why was it defined that way? [...] Why would we write 0000 to get zero?

我可以告诉你,但我必须杀了你.

I could tell you, but then I'd have to kill you.

乔治

后来,该线程产生了此错误报告,旨在摆脱这种特殊情况.在这里,Georg 说:

Later on, the thread spawned this bug report aiming to get rid of this special case. Here, Georg says:

我不记得这种故意更改的原因(从文档更改中可以看出).

I don't recall the reason for this deliberate change (as seen from the docs change).

我现在无法为这种更改找到充分的理由 [...]

I'm unable to come up with a good reason for this change now [...]

因此我们得到了它:这种不一致背后的确切原因已被时间遗忘.

and thus we have it: the precise reason behind this inconsistency is lost to time.

最后,请注意错误报告已被拒绝:对于 Python 3.x 的其余部分,将继续仅接受零整数上的前导零.

Finally, note that the bug report was rejected: leading zeros will continue to be accepted only on zero integers for the rest of Python 3.x.

相关文章