Python是解释的,还是编译的,或者两者都有?

根据我的理解:

解释语言是一种高级语言,由解释器(将高级语言转换为机器代码然后执行的程序)运行并执行;它每次处理一点点程序。

编译语言是一种高级语言,其代码首先由编译器(将高级语言转换为机器代码的程序)转换为机器代码,然后由执行器(另一个用于运行该代码的程序)执行。

如果我的定义错了,请指正。

现在回到Python,我对此有点困惑。无论在哪里,你都知道Python是一种解释型语言,但它被解释为一些中间代码(如字节码或IL),而被解释为机器代码。那么,哪个程序执行IM代码呢?请帮助我了解Python脚本是如何处理和运行的。

234101 次浏览

CPU实际上只能理解机器代码。对于解释型程序,解释器的最终目标是将程序代码“解释”为机器代码。然而,现代解释语言通常不会直接解释人类代码,因为它效率太低。

Python解释器首先读取人类代码,并在将其解释为机器代码之前将其优化为一些中间代码。这就是为什么你总是需要另一个程序来运行Python脚本,不像在c++中,你可以直接运行编译后的可执行代码。例如,c:\Python27\python.exe/usr/bin/python

首先,解释/编译不是语言的属性,而是实现的属性。对于大多数语言来说,大多数(如果不是所有的话)实现都属于一类,所以人们可能会说语言也是解释/编译的,但这仍然是一个重要的区别,因为它有助于理解,也因为有相当多的语言具有这两种类型的可用实现(主要在函数语言领域,参见Haskell和ML)。此外,还有C解释器和项目试图将Python的一个子集编译为C或c++代码(然后编译为机器代码)。

第二,编译不局限于本机代码的预先编译。更一般地说,编译器是将一种编程语言中的程序转换为另一种编程语言中的程序的程序(可以说,如果应用了重要的转换,您甚至可以拥有具有相同输入和输出语言的编译器)。JIT编译器编译本机机器代码在运行时,这可以提供非常接近甚至比提前编译的速度(取决于基准测试和比较的实现质量)。

但是为了停止吹毛求疵并回答你想问的问题:实际上(阅读:使用某种流行和成熟的实现),Python是编译。没有提前编译成机器代码(例如:"compiled"由受限制的和错误的,但遗憾的通用定义),"only"编译到字节码,但它仍然是编译,至少有一些好处。例如,语句a = b.c()被编译成一个字节流,当“拆解”时,看起来有点像load 0 (b); load_str 'c'; get_attr; call_function 0; store 1 (a)。这是一种简化,它实际上可读性较差,而且更低级——你可以用标准库dis模块进行实验,看看真正的东西是什么样子的。解释这个比从更高层次的表示进行解释要快。

字节码要么被解释(请注意,在理论和实际性能上,直接解释和首先编译到一些中间表示并解释它之间存在差异),就像参考实现(CPython)一样,要么在运行时被解释和编译到优化的机器代码,就像PyPy一样。

几乎,我们可以说Python是一种解释型语言。但是我们在python中使用了一次性编译过程的一部分,将完整的源代码转换为类似java语言的字节码。

答案取决于使用的是哪种python实现。如果你使用的是CPython的 (python的标准实现)或Jython(目标是与java编程语言集成),它首先被翻译成字节码,根据你使用的python实现,这个Bycode被定向到相应的虚拟机进行解释PVM (Python虚拟机)用于CPython, JVM (Java虚拟机)用于Jython。

但假设你正在使用PyPy,这是另一个标准的CPython实现。它将使用即时编译器

根据Python官方网站,它是解释的。

https://www.python.org/doc/essays/blurb/

Python是一种解释性的、面向对象的高级编程语言……

...

因为没有编译步骤…

...

Python解释器和广泛的标准库是可用的…

...

相反,当解释器发现错误时,它会引发 例外。当程序没有捕获异常时, 解释器输出堆栈跟踪

你写的python代码被编译成python字节码,它会创建扩展名为.pyc的文件。如果是编译,问题又来了,为什么不是编译语言。

注意,这不是传统意义上的编译。通常,我们会说编译是采用高级语言并将其转换为机器代码。但它是某种汇编。编译到中间代码,而不是机器代码(希望你现在得到它)。

回到执行过程,你的字节码,在pyc文件中,在编译步骤中创建,然后由相应的虚拟机执行,在我们的例子中,是CPython VM 时间戳(称为魔数)用于验证.py文件是否被更改,这取决于创建的新pyc文件。如果pyc是当前代码,则它简单地跳过编译步骤
< p > 如果(你懂Java) { < br > < br > Python代码像java一样被转换为字节码

}其他{ < br > < br > Python代码最初被翻译成一个叫做bytecode
的东西 接近机器语言,但不是实际的机器代码
所以每次我们访问或运行它时,字节码都会再次执行

} < / >强

是的,它既是编译语言也是解释语言。 那为什么我们一般称它为解释语言呢?

看到它是如何编译和解释的了吗?

首先我想说的是,如果你来自Java世界,你会更喜欢我的回答。

在Java中,源代码首先通过javac编译器转换为字节码,然后定向到JVM(负责生成用于执行的本机代码)。现在我想向你展示,我们将Java称为编译语言,因为我们可以看到它确实编译源代码,并通过以下方式给出. class文件(除了字节码之外什么都没有):

javac Hello.java ------->生成Hello.class文件

java你好 -------->将字节码指向JVM以执行

同样的事情也发生在python中,即首先通过编译器将源代码转换为字节码,然后定向到PVM(负责生成本机代码用于执行)。现在我想向你们展示,我们通常将Python称为解释语言,因为编译发生在幕后 当我们运行python代码时:

python Hello.py ------->直接执行代码,如果代码语法正确,我们可以看到输出

@ python Hello.py看起来像是直接执行,但实际上它首先生成由解释器解释的字节码,以产生用于执行目的的本机代码。

CPython的-承担编译和解释的责任。

如果你需要更多的细节,看看下面的几行:

正如我提到的,CPython的编译源代码,但实际编译是在cython的帮助下进行的,然后解释是在CPython的的帮助下进行的

现在让我们稍微讨论一下即时编译器在Java和Python中的作用

在JVM中存在Java解释器,它逐行解释字节码以获得用于执行的本机机器码,但当Java字节码由解释器执行时,执行将总是较慢。那么解决方案是什么呢?解决方案是即时编译器,它产生的本机代码可以执行得比解释的快得多。一些JVM供应商使用Java解释器,一些使用即时编译器。参考:点击这里

在python中,要绕过解释器以实现快速执行,请使用另一个python实现(PyPy)而不是CPython的点击这里用于python的其他实现,包括PyPy.

对于新手

在运行脚本之前,Python会自动将脚本编译为已编译的代码,即所谓的字节代码。

运行脚本不被认为是导入,也不会创建.pyc。

例如,如果你有一个脚本文件abc.py,它导入了另一个模块xyz.py,当你运行abc.py时,xyz.py, xyz.py。Pyc将被创建,因为xyz被导入,但没有abc。Pyc文件将被创建,因为abc.py没有被导入。

Python(解释器)是编译

证明:它甚至无法编译你的代码,如果它包含语法错误

示例1:

print("This should print")
a = 9/0

输出:

This should print
Traceback (most recent call last):
File "p.py", line 2, in <module>
a = 9/0
ZeroDivisionError: integer division or modulo by zero

代码编译成功。第一行被执行(print)第二行抛出ZeroDivisionError(运行时错误)。

示例2:

print("This should not print")
/0

输出:

  File "p.py", line 2
/0
^
SyntaxError: invalid syntax

结论:如果你的代码文件包含SyntaxError,编译失败时什么都不会执行。

对于刚开始使用python的人来说,这是一个很大的困惑,这里的答案有点难以理解,所以我会让它更简单。

当我们指示Python运行我们的脚本时,在我们的代码实际开始处理之前,Python会执行几个步骤:

  • 它被编译为字节码。
  • 然后路由到虚拟机。

当我们执行一些源代码时,Python会将其编译成字节代码。编译是一个转换步骤,字节代码是源代码的底层平台独立表示。

注意,Python字节码不是二进制机器码(例如,英特尔芯片的指令)。

实际上,Python通过将源代码中的每个语句分解为单独的步骤,将它们转换为字节码指令。执行字节码转换以加快执行速度。 字节代码的运行速度比原始源代码语句快得多。它有。

. Pyc扩展,如果它可以写入我们的机器,它将被写入

因此,下次我们运行相同的程序时,Python将加载.pyc文件并跳过编译步骤,除非它已被更改。Python自动检查源文件和字节码文件的时间戳,以知道何时必须重新编译。如果我们重新保存源代码,字节码将在下次程序运行时再次自动创建。

如果Python不能将字节代码文件写入我们的机器,我们的程序仍然可以工作。字节码在内存中生成,并在程序退出时简单地丢弃。但是由于.pyc文件加快了启动时间,我们可能希望确保它是为较大的程序编写的。

让我们来总结一下幕后发生了什么。 当Python执行程序时,Python将.py读入内存,并解析它以获得字节码,然后继续执行。对于程序导入的每个模块,Python首先检查.pyo或.pyc中是否有预编译的字节码版本,其时间戳对应于其.py文件。Python使用字节码版本(如果有的话)。否则,它会解析模块的.py文件,将其保存到.pyc文件中,并使用刚刚创建的字节码

字节代码文件也是传递Python代码的一种方式。Python仍然会运行一个程序,如果它能找到的都是。Pyc文件,即使原始的.py源文件不在那里。

Python虚拟机(PVM)

一旦我们的程序被编译成字节码,它就会被传送到Python虚拟机(PVM)执行。PVM不是一个单独的程序。不需要自行安装。实际上,PVM只是一个大循环,一个接一个地遍历我们的字节码指令,以执行它们的操作。PVM是Python的运行时引擎。它总是作为Python系统的一部分出现。它是真正运行脚本的组件。从技术上讲,这只是所谓的Python解释器的最后一步。

它真的这取决于语言的实现被使用!不过,在任何实现中都有一个常见的步骤:你的代码首先被编译(翻译)为中间代码——介于你的代码和机器(二进制)代码之间的代码——称为字节码(存储在.pyc文件中)。注意,这是一个一次性步骤,除非修改代码,否则不会重复。

这个字节码在每次运行程序时都会被执行。怎么做?好吧,当我们运行程序时,这个字节码(在.pyc文件中)作为输入传递给虚拟机1 .使用实例——允许我们的程序被执行的运行时引擎——执行它。

根据语言实现的不同,VM将解释字节码(在CPython2实现的情况下)或JIT-compile3.字节码(在PyPy4实现的情况下)。

笔记:

1一个计算机系统的仿真

2一个字节码解释器;该语言的参考实现,用C和Python编写,使用最广泛

在程序执行期间(在运行时)进行的3.编译

4一个字节码JIT编译器;CPython的替代实现,用RPython (Restricted Python)编写——通常比CPython运行得更快

在我看来,Python被归入解释器类别,因为它被设计成能够完全处理(从Python代码到在cpu中执行)单个Python语句。也就是说,你写了一个语句,你可以执行它,如果没有错误,然后得到相应的结果。

有一个中间代码(如字节码),我认为没有区别,把它整体归类为编译器。虽然这个组件(中间代码生成)通常是编译器的一部分,但它也可以用于解释器。参见解释器https://en.m.wikipedia.org/wiki/Interpreter_(计算)的wiki定义。在执行速度方面增加效率是至关重要的一环。有了缓存,它甚至更强大,如果你没有改变当前程序范围内的代码,你可以跳过沉重的处理步骤,如词汇,语义分析,甚至一些代码优化。

已经有人说过,“解释/编译不是语言的属性,而是实现的属性”。Python既可以用于解释模式,也可以用于编译模式。当您直接从终端或cmd运行python代码时,python解释器将启动。现在,如果您编写任何命令,那么该命令将被直接解释。如果你使用一个包含Python代码的文件,并在IDE中运行它或使用命令提示符,它将首先被编译,整个代码将被转换为字节码,然后它将运行。所以这取决于我们如何使用它。

这似乎是语义上的问题。我想大多数人都会推断编译的结果通常是机器代码。考虑到这一点,我对自己说,python是没有编译的。不过我可能错了,因为compile实际上意味着转换到较低级别,所以从源代码转换到字节码也是编译。