是Python解释,编译,还是两者兼而有之?

时间:2011-07-31 13:31:52

标签: python interpreted-language

根据我的理解:

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

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

如果我的定义错误,请纠正我。

现在回到Python,我对此感到困惑。在任何地方,您都了解到Python是一种解释型语言,但它被解释为一些中间代码(如字节代码或IL)和而不是到机器代码。那么哪个程序执行IM代码?请帮助我理解如何处理和运行Python脚本。

14 个答案:

答案 0 :(得分:190)

首先,解释/编译不是语言的属性,而是实现的属性。对于大多数语言而言,大多数(如果不是全部)实现都属于一个类别,因此可以保存一些单词,说语言也被解释/编译,但它仍然是一个重要的区别,因为它有助于理解,因为有很多语言两种类型的可用实现(主要在函数式语言领域,请参阅Haskell和ML)。此外,有C语言解释器和项目试图将Python的一个子集编译为C或C ++代码(以及随后的机器代码)。

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

但是要停止挑剔并回答你想问的问题:实际上(阅读:使用一些有点流行和成熟的实现),Python 编译。未提前编译为机器代码(即由受限制和错误的“编译”,但很常见的定义),“仅”编译为bytecode,但它仍然编译至少具有一些好处。例如,语句a = b.c()被编译为字节流,当“反汇编”时,它看起来有点像load 0 (b); load_str 'c'; get_attr; call_function 0; store 1 (a)。这是一种简化,它实际上不太可读,而且更低级 - 您可以尝试使用标准库dis module并查看真实交易的样子。解释这比从更高层次的表示中解释更快。

对字节码进行解释(注意理论和实际性能之间存在差异,直接解释和首次编译到某些中间表示并解释),与参考实现(CPython)一样,或两者都解释并在运行时编译为优化的机器代码,与PyPy一样。

答案 1 :(得分:26)

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

Python解释器首先读取人工代码并将其优化为一些直接代码,然后再将其解释为机器代码。这就是为什么你总是需要另一个程序来运行Python脚本,这与C ++不同,你可以直接运行可执行文件。例如c:\ Python27 \ python.exe或/ usr / bin / python。

答案 2 :(得分:19)

答案取决于正在使用的python实现。如果你正在使用让我们说 CPython (python的标准实现)或 Jython (目标是与java编程语言集成),它首先被翻译成字节码,并且根据您正在使用的python的实现,此 bycode被定向到相应的虚拟机以进行解释。适用于CPython的 PVM (Python虚拟机)和适用于Jython的 JVM (Java虚拟机)。

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

答案 3 :(得分:9)

根据python.org,它是一名翻译。

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

  

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

...

  

由于没有编译步骤......

...

  

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

...

  

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

答案 4 :(得分:3)

如果(您知道Java){

Python代码像Java一样转换为字节码。
每次尝试访问该字节码时,都会再次执行该字节码。

}其他{

最初,Python代码被转换为字节码
,这相当 接近机器语言,但不是实际的机器代码
因此,每次我们访问或运行它时,字节码都会再次执行

}

答案 5 :(得分:2)

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

答案 6 :(得分:1)

对于开始使用python的人们来说,这是一个很大的困惑,这里的答案有点难以理解,因此我将使其变得更容易。

当我们指示Python运行脚本时,在代码真正开始崩溃之前,Python需要执行一些步骤:

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

当我们执行源代码时,Python会将其编译为字节代码。编译是一个翻译步骤,字节码是源代码的低层平台无关表示。请注意,Python字节码不是二进制机器码(例如,用于Intel芯片的指令)。

实际上,Python通过将源代码的每个语句分解为单独的步骤,将它们转换为字节代码指令。执行字节码转换以加快执行速度。 字节码可以比原始源代码语句快得多地运行。它具有has.pyc扩展名,如果可以写入我们的计算机,则会被写入。

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

如果Python无法将字节代码文件写入我们的机器,则我们的程序仍然有效。字节代码在内存中生成,并在程序退出时被简单丢弃。但是,因为.pyc文件可以加快启动时间,所​​以我们可能要确保已为大型程序编写了该文件。

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

字节码文件也是传送Python代码的一种方式。如果Python仅能找到are.pyc文件,即使原始.py源文件不存在,Python仍将运行该程序。

Python虚拟机(PVM)

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

答案 7 :(得分:1)

这真的取决于所用语言的实现方式!!不过,在任何实现中都有一个通用步骤:您的代码首先被编译(翻译)为中间代码-在您的代码和计算机(二进制)代码之间-被称为 bytecode (存储在.pyc文件中) 。请注意,这是一次性步骤,除非您修改代码,否则不会重复。

并且每次运行程序时都会执行该字节码。怎么样?好了,当我们运行程序时,此字节码(在.pyc文件中)将作为输入传递给虚拟机(VM) 1 -运行时引擎允许我们的程序要执行-执行它。

取决于语言的实现,VM将解释字节码(对于CPython 2 实现)或JIT-compile 3 (对于CPython 2 实现)。 PyPy 4 实现)。

注释

1 计算机系统的仿真

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

3 编译是在程序执行期间(在运行时)完成的

4 字节码JIT编译器;用RPython(受限Python)编写的CPython的另一种实现-通常比CPython运行得快

答案 8 :(得分:0)

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

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

回到执行过程,在编译步骤中创建的pyc文件中的字节码然后由适当的虚拟机执行,在我们的例子中是CPython VM 时间戳(称为幻数)用于验证.py文件是否已更改,具体取决于创建的新pyc文件。如果pyc是当前代码,那么它只是跳过编译步骤。

答案 9 :(得分:0)

是的,它既是编译语言又是解释语言。 那为什么我们通常将其称为解释语言?

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

首先,我想告诉您,如果您来自Java世界,那么您会更喜欢我的答案。

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

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

java Hello -------->将字节码定向到 JVM 以用于执行目的

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

python Hello.py ------->直接执行代码,我们可以看到输出证明该代码在语法上是正确的

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

CPython -负责编译和解释。

如果需要更多详细信息,请查看以下几行

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

的帮助下进行的>

现在让我们谈谈即时编译器在Java和Python中的作用

在JVM中,存在Java解释器,该解释器逐行解释字节码以获取用于执行目的的本机机器代码,但是当Java字节码由解释器执行时,执行总是较慢。那么解决方案是什么?解决方案是及时编译器,它可以生成本机代码,其执行速度比解释性要快得多。一些JVM供应商使用 Java解释器,而一些使用即时编译器。参考:click here

在python中绕过解释器以实现快速执行,请使用另一个python实现( PyPy )代替 CPython click here用于python的其他实现,包括 PyPy

答案 10 :(得分:0)

对于新手

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

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

例如,如果您有一个脚本文件abc.py导入了另一个模块xyz.py,则在运行abc.py时,由于导入了xyz,将创建xyz.pyc,但不会创建abc.pyc文件因为未导入abc.py。

答案 11 :(得分:0)

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 ,则编译失败将不会执行任何操作。

答案 12 :(得分:0)

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

答案 13 :(得分:-2)

在我看来,Python 被置于解释器类别中,因为它旨在能够完全处理(从 Python 代码到在 CPU 中执行)单个 Python 语句。 IE。你写了一条语句就可以执行,如果没有错误就得到相应的结果。

拥有中间代码(如字节码),我认为将其总体归类为编译器并没有什么不同。虽然这个组件(中间代码生成)通常是编译器的一部分,但它也可以用于解释器。请参阅解释器 https://en.m.wikipedia.org/wiki/Interpreter_(computing) 的 wiki 定义。它是在执行速度方面提高效率的关键部分。有了缓存,它就更强大了,这样如果您没有更改当前程序范围内的代码,您就可以跳过繁重的处理步骤,例如词法、语义分析甚至一些代码优化。