柏拉图:解释型语言呢?
苏格拉底:解释型语言是依赖于一个单独的程序(恰如其分地称为解释器)来实际运行代码的语言 。解释型语言不需要程序员先运行编译器 。因此 , 在程序运行时 , 您犯的任何错误都会被捕获 。Python 是一种解释型语言,没有单独的编译器,您犯的所有错误都会在运行时捕获 。
柏拉图:如果 Python不是一种编译语言,那么为什么标准库包含名为 py_compile and compileall 的模块?
苏格拉底:嗯,这些模块只是将 Python转换为字节码 。他们不会将 Python 转换为机器代码,因此 Python 仍然是一种解释型语言 。
柏拉图:那么,Python和 Java都转换为字节码了吗?
苏格拉底:对 。
柏拉图:那么,为什么Python是一种解释型语言,而 Java却是一种编译型语言呢?
苏格拉底:因为 Python 中的所有错误都是在运行时捕获的 。(ps:请注意这句话)
- 回合一

文章插图
图片
检测到的第一个报错位于源码的最后一行 。可以看到:在运行第一行代码之前,Python 必须读取整个源码文件
如果你脑子里有一个关于【解释型语言】的定义 , 其中包括”解释型语言按顺序读取代码,一次运行一行” , 我希望你忘掉它
我还没有深入研究 CPython 解释器的源码来验证这一点,但我认为这是第一个检测到的报错的原因是 Python 3.12 所做的第一个步骤是扫描(scanning ) , 也称为词法分析
扫描器将整个文件转换为一系列标记(token) , 然后继续进行下一阶段 。
扫描器扫描到源码最后一行的字符串字面值末尾少了个引号 , 它希望把整个字符串字面值转换成一个 token ,但是没有结束引号它就转换不了
在 Python 3.12 中,扫描器首先运行,所以这也是为什么第一个报错是unterminated string literal
- 回合二

文章插图
图片
我们现在来执行代码,看下哪个会首先报错

文章插图
图片
这次是第二行报错!同样,我没有去查看 CPython 的源码,但是我有理由确定扫描的下一阶段是解析(parsing),也称为语法分析
在运行代码之前会先解析源码,这意味着 Python 不会看到第一行的错误 , 而是在第二行报错
我要指出我为这个小游戏而编写的代码是完全没有意义的 , 并且对于如何修复 bug 也没有正确的答案 。我的目的纯粹是编写错误然后发现 python 解释器现在处在哪个阶段
我不知道 print() = None可能是什么意思 , 所以我将通过将其替换为print(None)来解决这个问题,这也没有意义,但至少它在语法上是正确的 。
- 回合三

文章插图
图片
回想一下 , 语法错误在回合二的时候优先显示了出来,在回合三还会一样吗

文章插图
图片
没错!第三行的语法错误优先于第一行的错误
正如回合二一样,Python 解释器在运行代码之前会先解析源码,对其进行语法分析
这意味着 Python 不会看到第一行的错误,而是在第三行报错
你可能想知道为什么我在一个文件中插入了两个 SyntaxError , 难道一个还不够表明我的观点吗?
这是因为 Python 版本的不同会导致结果的不同,如果你在 Python3.8 或者更早的版本去运行代码,那么结果如下
在 Python 3.8 中,第 2 轮报告的第一个错误消息位于第 3 行:

文章插图
图片
修复第三行的错误之后,Python 3.8 在第 2 行报告以下错误消息:

文章插图
图片
为什么 Python 3.8 和 3.12 报错顺序不一样?是因为 Python 3.9 引入了一个新的解析器 。这个解析器比以前的 naïve 解析器功能更强大
推荐阅读
- Python 真的很糟糕吗?
- Python编程必备:掌握列表遍历的六种神级技巧!
- 高性能Python开发:解密FastAPI的高并发秘籍!
- Python使用VTK系列之安装指南
- 使用Ray轻松进行Python分布式计算
- 掌握Python中的闭包技巧
- 用Python库优化机器学习工作流程
- Python脚本支持OC代码重构实践:模块调用关系分析
- 如何使用 Python 和 python-docx 库读取、写入和操作 Word 文件
- 你真的理解Python Qt6基础知识中的信号和槽机制吗?
