236

据我了解:

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

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

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

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

4

15 回答 15

292

首先,解释/编译不是语言的属性,而是实现的属性。对于大多数语言,如果不是所有的实现都属于一个类别,那么可能会省下几句话来说明该语言也被解释/编译,但这仍然是一个重要的区别,因为它有助于理解并且因为有很多语言具有两种可用的实现(主要在函数式语言领域,请参阅 Haskell 和 ML)。此外,还有 C 解释器和项目试图将 Python 的子集编译为 C 或 C++ 代码(随后编译为机器代码)。

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

但是要停止吹毛求疵并回答您要问的问题:实际上(阅读:使用某种流行且成熟的实现),Python 是编译的。不提前编译成机器码(即“编译”受限制和错误,但可惜通用定义),“只”编译成字节码,但它仍然是编译至少有一些好处。例如,该语句a = b.c()被编译成一个字节流,当“反汇编”时,它看起来有点像load 0 (b); load_str 'c'; get_attr; call_function 0; store 1 (a). 这是一种简化,实际上它的可读性更低,而且更底层——您可以尝试使用标准库dis模块,看看真正的交易是什么样的。

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

于 2011-07-31T13:43:23.793 回答
50

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

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

于 2011-07-31T13:40:52.627 回答
37

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

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

于 2016-09-06T18:10:20.677 回答
24

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

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

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

...

由于没有编译步骤...

...

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

...

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

于 2017-01-24T14:32:45.187 回答
19

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

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

首先,我想告诉您,如果您来自 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的帮助下进行解释

现在让我们稍微谈谈Just-In-Time编译器在Java和Python中的作用

在 JVM 中存在 Java 解释器,它逐行解释字节码以获取本机机器码以用于执行目的,但是当 Java 字节码由解释器执行时,执行总是会变慢。那么解决方案是什么?解决方案是即时编译器,它生成的本机代码可以比解释的速度更快地执行。一些 JVM 供应商使用Java Interpreter,一些使用Just-In-Time 编译器。参考:点这里

在 python 中绕过解释器以实现快速执行使用另一个 python 实现(PyPy)而不是CPython单击此处查看其他 python 实现,包括PyPy

于 2019-05-10T10:18:52.407 回答
11

对于刚开始使用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 解释器的最后一步。

于 2020-07-11T12:35:10.957 回答
6

If ( You know Java ) {

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

} else {

Python 代码最初被翻译成一种叫做字节码的东西
,它非常接近机器语言,但不是真正的机器码
,所以每次我们访问或运行它时,字节码都会再次执行

}

于 2018-09-02T11:34:39.827 回答
4

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

每次运行程序时都会执行该字节码。如何?好吧,当我们运行程序时,这个字节码(在 .pyc 文件中)作为输入传递给虚拟机(VM)1 - 允许我们执行程序的运行时引擎 - 执行它。

根据语言实现,VM 将解释字节码(在 CPython 2实现的情况下)或 JIT 编译3(在 PyPy 4实现的情况下)。

备注

1计算机系统仿真

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

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

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

于 2020-10-10T13:33:30.683 回答
2

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

于 2013-04-10T05:12:06.367 回答
2

对于新手

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

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

例如,如果你有一个脚本文件 abc.py 导入了另一个模块 xyz.py,当你运行 abc.py 时,由于 xyz 被导入,将创建 xyz.pyc,但从 abc 开始不会创建 abc.pyc 文件。 py 没有被导入。

于 2019-08-07T08:25:07.227 回答
1

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任何内容,则编译失败将执行。

于 2019-09-04T15:20:38.833 回答
0

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

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

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

于 2017-11-08T10:23:49.213 回答
0

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

于 2021-07-25T15:09:07.870 回答
0

似乎是语义的一个案例。我认为我们中的大多数人推断编译的通常结果是机器代码。考虑到这一点,我对自己说 python 没有被编译。我会错的,因为编译确实意味着转换到较低级别,所以从源代码转换为字节码也是编译。

于 2021-10-13T04:46:55.307 回答
-2

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

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

于 2021-03-27T08:17:43.270 回答