为什么Python 3允许“00”作为0的文字而不允许“01”作为1的文字?

为什么Python 3允许“00”作为0的文字而不允许“01”作为1的文字呢? 有没有很好的理由? 这种不一致让我感到困惑。 (而且我们正在谈论Python 3,它有意破坏了后向兼容性,以实现一致性等目标。)

例如:

>>> 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 ::= 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" 

除了可以存储在可用存储器中的内容之外,整数文字的长度没有限制。

请注意,不允许使用非零十进制数的前导零。 这是为了消除C语言中的八进制文字,Python在3.0以前使用。

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

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

SVN commit r55866在tokenizer中实现了PEP 3127,它禁止旧的0<octal>数字。 不过,好奇的是,它也增加了这个注意:

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

带有一个特殊的nonzero标志,如果下面的数字序列包含非零数字,则该标志只会引发SyntaxError

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

这个PEP提出,使用前导零指定八进制数的能力将从Python 3.0中的语言(以及2.6的Python 3.0预览模式)中被移除,并且每当前导“0”被引发时,将会引发SyntaxError紧接着是另一个数字

(重点是我的)

所以,允许多个零的这个事实在技术上违反了PEP,并且基本上由Georg Brandl作为一个特例来实现。 他做了相应的文档更改,注意到"0"+decimalinteger octinteger的有效情况(之前已经在octintegeroctinteger )。

我们可能永远不知道为什么Georgselect使"0"+有效 – 它可能永远在Python中仍然是一个奇怪的angular落案例。


更新 [2015年7月28日]:这个问题引发了一个关于python思想的热烈讨论 , Georg在其中提到 :

Steven D'Aprano写道:

为什么这样定义? […]为什么我们会写0000来获得零?

我可以告诉你,但是我不得不杀了你。

乔治·

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

我不记得这个故意改变的原因(从文档改变看)。

我现在无法想出这个改变的一个好的理由[…]

因此我们拥有了:这种不一致背后的确切原因已经失去了时间。

最后,请注意,这个错误报告被拒绝了:对于其他的Python 3.x而言,前导零将仅被接受为零整数。

这是一个特例( "0"+

2.4.4。 整数文字

整数文字用下面的词汇定义来描述:

整数:: =十进制整数|  octinteger |  hexinteger |  bininteger
 decimalinteger :: = nonzerodigit数字* |  “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”

如果你看语法,很容易看出0需要一个特例。 我不确定为什么“ + ”被认为是必要的。 有时间通过​​开发邮件列表来挖掘…


有趣的是,在Python2中,多于一个0被parsing为一个octinteger (最终结果仍然是0

 decimalinteger :: = nonzerodigit数字* |  “0”
 octinteger :: =“0”(“o”|“O”)十进制+ |  “0”octdigit +

Python2使用前导零来指定八进制数字:

 >>> 010 8 

为了避免这种(误导?)行为,Python3需要明确的前缀0b0o0x

 >>> 0o10 8