我知道的许多语言(如 C++、C、Rust 等)一次打印多条错误消息。那为什么python只打印一条错误信息呢?
3 回答
首先,我假设我们谈论的是语法错误,即那些可以(并且应该)被编译器检测和报告的错误。
它主要是一种设计选择。Python 基本上建立在一切都应该在运行时完成的概念之上。并且编译器故意保持尽可能简单。
简单易懂或复杂复杂: 简单地说,您可以选择使用易于理解和维护的非常简单的编译器,或者您拥有具有复杂程序分析和优化的复杂机器。
C、C++ 和 Rust 等语言的优势在于在编译期间对代码进行了大量优化,因此采用了高度复杂和极其复杂的编译器的第二条路线。处理语法错误是他们不那么令人印象深刻的壮举之一。
另一方面,Python 则另辟蹊径。实际上,一般来说,Python 编译器完全不可能在不实际运行的情况下预测一段 Python 代码正在做什么——这首先排除了所有有趣的优化机会,因此复杂的编译器不会真正有道理,反正。因此,保持 Python 的编译器简单而专注于运行时优化是正确的选择。但它的缺点是编译器在发现错误时会简单地退出。
为了提供更多上下文...
1.错误恢复
在编译器中处理错误并从语法错误中恢复是很困难的。
编译器通常非常擅长将(语法上)正确的程序快速有效地翻译成代表原始程序的机器代码。但是,如果出现语法错误,编译器往往无法猜出程序员的初衷,因此不清楚如何处理错误的代码。
这是一个非常简单的例子:
pen color("red")
显然,这里有问题,但如果没有进一步的上下文,就无法判断这行的原意是pen = color("red")
,pencolor("red")
还是pen.color("red")
完全其他的东西。
如果编译器想要继续查看程序的其余部分(并因此发现潜在的更多语法错误),它需要一个关于如何应对这种情况并恢复以继续前进的策略:它需要一个错误恢复策略。这可能就像跳过整行或单个标记一样简单,但是对此没有明确的“正确”解决方案。
2. Python的编译器
Python 一次编译一个符号。
Python 当前的编译器通过一次查看一个符号来工作(称为LL(1)
编译器)。这使得为 Python 自动构建编译器变得非常简单,而且非常快速和高效。但这意味着在某些情况下,尽管存在“明显的”语法错误,Python 仍会愉快地继续编译程序,直到它真正丢失为止。
看看这个例子:
x = foo(
y = bar()
if x > y:
作为人类,我们很快就会在第 1 行中看到缺少的右括号。但是,从编译器的角度来看,这看起来很像带有命名参数的调用,如下所示:
x = foo(y = bar() if x > y else 0)
因此,Python 只会在遇到第 3 行的冒号时才注意到有问题——第一个不符合其“假设”的符号。但到那时,很难弄清楚如何处理这段代码,以及如何正确恢复:在这种情况下你是否只是跳过冒号?或者你应该早点回去纠正一些事情——如果是这样,你要往前走多远?
3. 后续错误
错误恢复会产生“幽灵”错误。
在上面的第一个示例中,编译器可以跳过整行并继续前进而没有任何问题。但是在某些情况下,如何从语法错误中恢复的选择会影响(可能)接下来的一切,如下例所示:
deffoo(x):
这背后的意图可能是def foo(x):
或只是一个 call deffoo(x)
。但是这种区别决定了编译器将如何查看后面的代码,或者报告缩进错误,或者可能是return
函数外部等。
错误恢复的危险在于编译器的猜测实际上可能是错误的,这可能会导致一系列报告的后续错误——甚至可能不是真正的错误,而是编译器错误决定造成的鬼魂。
底线:正确进行错误恢复和错误报告非常困难。因此,Python 选择只报告它遇到的第一个语法错误是明智的,并且适用于大多数用户和情况。
我实际上已经编写了一个具有更复杂的错误检测的解析器,它可以列出它在 Python 程序中发现的所有错误。但是根据我的经验,除了第一个错误之外,太多的附加错误只是垃圾,因此我总是坚持只显示程序中的第一个错误。
很难回答确切的原因。我无法查看 C-python、jython、pypy 或其他开发人员的脑袋。
许多错误只会在运行时看到,因为 python 是一种没有严格类型的解释语言。
但是,如果没有语法错误,每个文件都会编译为字节码。
所以对于语法错误,我不能给你原因,因为它在技术上应该是可行的。pylint
但是,当我使用类似工具或flake8
为我检查代码时,我从来没有遇到过这个问题。
这些工具可以检测到多个错误,并给出很多关于编码风格的警告。
因此,我无法告诉您原因,而只能告诉您如何一次性解决多个错误。
这些工具可以配置为仅显示某些类型的错误。
要安装一个或另一个工具,只需键入:
pip install flake8
或pip install pylint
然后只键入flake8
或pylint
在所有代码所在的目录中键入或键入flake8 <filename>
或pylint <filename>
仅检查一个文件。
请注意,许多 IDE(例如 Microsoft Visual Studio Code、Pycharm 等)可以配置为自动为您运行这些工具,甚至在您执行代码之前就发出任何问题。
C或C ++使用编译器编译然后执行,但python是一种解释语言,这意味着解释器读取每一行,然后在解释器在它停止的程序行中看到错误时执行它,并以其他解释语言显示错误,如JS 也是一样。我希望你的问题得到解决,但如果你想阅读更多,你可以谷歌“解释和编译语言”或看到这个