【问题标题】:Why does Python 3 allow "00" as a literal for 0 but not allow "01" as a literal for 1?为什么 Python 3 允许“00”作为 0 的文字,但不允许“01”作为 1 的文字?
【发布时间】:2015-10-05 12:20:47
【问题描述】:

为什么 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
>>>

【问题讨论】:

  • 现在不能删除,否则会破坏对本题的向后兼容性!

标签: python python-3.x integer literals leading-zero


【解决方案1】:

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

>>> 010
8

为避免这种(误导性?)行为,Python3 需要显式前缀 0b0o0x

>>> 0o10
8

【讨论】:

  • 问题仍然存在:为什么00 被允许? (还有0000000等)
  • @MichaelGeary:可能是因为它不能模棱两可(00000000 为 0,无论基数如何)并且删除它会不必要地破坏代码?还是很奇怪。
  • @RemcoGerlich 如果我没记错的话,01 也是 1,不管基数如何。
  • @Holt:但允许“0”+“1”?作为一个特殊情况可能会更加混乱。
  • @RemcoGerlich 从来没有说过不会;)我只是说can't be ambiguous 不是一个论点,因为01 也不能模棱两可。 IMO,00 的情况只是一个特例,因为它不应该是0
【解决方案2】:

这是一个特例 ("0"+)

2.4.4. Integer literals

整数文字由以下词法定义描述: 整数 ::= 十进制整数 |八进制 |六角整数 |二进制整数 十进制整数 ::= 非零位数字* | "0"+ 非零数字 ::= "1"..."9" 数字 ::= "0"..."9" 八进制数 ::= "0" ("o" | "O") 八进制数+ hexinteger ::= "0" ("x" | "X") hexdigit+ bininteger ::= "0" ("b" | "B") bindigit+ 八位数字 ::= "0"..."7" 十六进制数字 ::= 数字 | "a"..."f" | “A”……“F” 二进制数字 ::= "0" | “1”

如果你看一下语法,很容易看出0 需要一个特殊情况。我不确定为什么'+'在那里被认为是必要的。是时候深入了解开发者邮件列表了...


有趣的是,在 Python2 中,不止一个 0 被解析为 octinteger(但最终结果仍然是 0

十进制整数 ::= 非零位数字* | “0” 八进制数 ::= "0" ("o" | "O") 八进制数+ | “0”八位数字+

【讨论】:

  • 知道为什么会有"0"+ 而不是"0" 吗?
  • @lejlot,还没有——但我很感兴趣。这绝对是规范的一部分
【解决方案3】:

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"+ 作为一个非常特殊的情况是合法的,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 在标记器中实现了 PEP 3127,它禁止旧的 0&lt;octal&gt; 数字。然而,奇怪的是,它还添加了这个注释:

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

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

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

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

(强调我的)

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

我们可能永远不会确切地知道为什么 Georg 选择使 "0"+ 有效 - 它可能永远是 Python 中一个奇怪的角落案例。


更新 [2015 年 7 月 28 日]:这个问题导致了一个关于 python-ideas 的lively discussion threadGeorg chimed in

史蒂文·达普拉诺写道:

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

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

乔治

后来,产生了this bug report 的线程,旨在摆脱这种特殊情况。这里,Georg says

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

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

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

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

【讨论】:

  • 你为什么说“我们可能永远不会确切地知道 Georg 为什么选择……”?如果认识他的人看到这个帖子并告诉他,那么他可能会来给出答案! (除非你知道他永远拒绝讨论他过去的 Python 工作或类似情况)
  • 我不明白他们为什么不只是制作第二个 Python 2 octinteger case "0" octdigit*0 是 C/C++ 中的八进制文字。
  • 其实英文在这方面有点含糊。 “另一个”一词可以表示“再一个”,也可以表示“另一个”。对 PEP 3127 中粗体引述的一种有效英文解释是表示“只要前导 '0' 后面紧跟 '0' 以外的数字,就会引发 SyntaxError”我不确定这是否是实际意图(虽然这种解释似乎得到了实际代码的支持),但无论如何我认为在没有额外澄清该句子的情况下说 PEP 在技术上被违反是不准确的。
  • @GrandOpener:请注意,001 是非法的,而您的解释会使其合法(因为“立即”的含义应该非常明确)。
  • 好点。所以肯定违反了PEP;模棱两可的是它被违反的确切性质。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-31
  • 2015-10-04
  • 2012-03-07
  • 1970-01-01
  • 2020-09-23
  • 1970-01-01
相关资源
最近更新 更多