<p><em>首先,我假设我们讨论的是语法错误,即编译器可以(也应该)检测和报告的语法错误</em></p>
<p>这主要是一种设计选择。Python基本上是基于这样一个概念构建的,即一切都应该在运行时完成。而且编译器故意保持尽可能简单</p>
<p><strong>简单易懂,或复杂复杂:</strong>
简单地说,您可以选择使用易于理解和维护的非常简单的编译器,或者使用具有复杂程序分析和优化的复杂机器</p>
<P>语言如C、C++、Rand在编译过程中从强优化代码中汲取力量,因此采用了高度复杂和极其复杂的编译器的第二条路线。处理语法错误是他们不那么令人印象深刻的壮举之一</p>
<p>另一方面,Python走了另一条路。事实上,一般来说,Python编译器在不实际运行Python代码的情况下是不可能预测一段Python代码到底在做什么的,这首先排除了所有有趣的优化机会,因此,一个复杂的编译器无论如何都没有意义。因此,保持Python编译器的简单并关注运行时优化是正确的选择。但它的缺点是编译器在发现错误时会直接退出</p>
<hr/>
<p>给我一点背景</p>
<h3>一,。错误恢复</h3>
<p><em>在编译器中处理错误并从语法错误中恢复是很困难的</em></p>
<p>编译器通常非常擅长将(语法上)正确的程序快速高效地翻译成代表原始程序的机器代码。但是,如果出现<em>语法错误</em>,编译器通常无法猜测程序员的原始意图,因此不清楚如何处理错误代码</p>
<p>下面是一个非常简单的例子:</p>
<pre class="lang-py prettyprint-override"><code>pen color("red")
</code></pre>
<p>显然,这里有一些错误,但如果没有进一步的上下文,就不可能判断这一行的初衷是<code>pen = color("red")</code>、<code>pencolor("red")</code>、<code>pen.color("red")</code>还是完全其他什么</p>
<p>如果编译器想继续查看程序的其余部分(从而发现潜在的更多语法错误),它需要一个如何处理这种情况并恢复的框架,以便继续:它需要一个<em>错误恢复策略</em>。这可能像跳过整行或单个令牌一样简单,但没有明确的“正确”解决方案</p>
<h3>二,。Python的编译器</h3>
<p><em>Python一次编译一个符号</em></p>
<p>Python当前的编译器一次只查看一个符号(称为<code>LL(1)</code>编译器)。这使得为Python自动构建编译器变得非常简单,而且非常快速高效。但这意味着,在某些情况下,尽管出现了“明显的”语法错误,Python仍会愉快地继续编译程序,直到程序真正丢失为止</p>
<p>看看这个例子:</p>
<pre class="lang-py prettyprint-override"><code>x = foo(
y = bar()
if x > y:
</code></pre>
<p>作为人类,我们很快就能看到第1行中缺少的右括号。但是,从编译器的角度来看,这看起来更像是一个带有命名参数的调用,类似于:</p>
<pre class="lang-py prettyprint-override"><code>x = foo(y = bar() if x > y else 0)
</code></pre>
<p>因此,Python只会在第3行中的冒号处注意到有问题,冒号是第一个与其“假设”不符的符号。但在这一点上,很难弄清楚如何处理这段代码,以及如何正确地恢复:在这种情况下,是否跳过冒号?或者你应该回到过去,在更早的时候纠正一些事情,如果是这样的话,你要走多远</p>
<h3>三,。跟进错误</h3>
<p><em>错误恢复会产生“重影”错误</em></p>
<p>在上面的第一个示例中,编译器可以跳过整条线,毫无问题地继续前进。但在某些情况下,如何从语法错误中恢复的选择(可能)会影响下面的一切,如本例所示:</p>
<pre class="lang-py prettyprint-override"><code>deffoo(x):
</code></pre>
<p>这背后的意图可能是<code>def foo(x):</code>,也可能只是一个调用<code>deffoo(x)</code>。但是这种区别决定了编译器将如何查看后面的代码,或者报告缩进错误,或者可能报告函数外部的<code>return</code>,等等</p>
<p>错误恢复的危险在于编译器的猜测可能实际上是错误的,这可能导致一系列报告的后续错误,这些错误甚至可能不是真正的错误,而是由编译器的错误决定造成的幽灵</p>
<hr/>
<p><strong>底线:</strong>要正确地进行错误恢复和错误报告非常困难。因此,Python选择只报告它遇到的第一个语法错误是明智的,对大多数用户和情况都适用</p>
<p>实际上,我已经编写了一个<a href="https://github.com/Tobias-Kohn/TigerPython-Parser" rel="nofollow noreferrer">parser with more sophisticated error detection</a>,它可以列出它在Python程序中发现的所有错误。但根据我的经验,除了第一个错误之外,还有太多的额外错误都是垃圾,因此我总是坚持只显示程序中的第一个错误</p>