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


190

据我了解:

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

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

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

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



2
每当导入库时,Python都会创建.pyc文件(所谓的byecode)。AFAIK字节码只能加快加载时间,而不能加快执行时间。
Jesvin Jose

2
@aitchnyu:在.pyc文件中缓存字节码确实确实可以加快加载速度,但是只是在执行之前将Python代码编译为字节码的情况下。尽管我认为没有专门针对Python进行过尝试,但是其他语言实现表明字节码确实比纯AST甚至更难解析的源代码更容易高效地解释。例如,较旧的Ruby版本是从AST解释而来的,而AFAIK在较新版本中的表现要好得多,后者可以编译为字节码。

不想听起来很粗鲁,但不是我的意思(但不如您所知)吗?
Jesvin Jose

1
@aitchnyu:我不知道你的意思。我只知道您的评论并不正确,但是为某些背景信息提供了很好的机会,为什么它只会加快加载时间,所以我决定添加该信息。没有冒犯的意思:)

Answers:


231

首先,解释/编译不是语言的属性,而是实现的属性。对于大多数语言,大多数(如果不是全部)实现都归为一类,因此可以省去几个词来说明该语言也可以解释/编译,但这仍然是一个重要的区别,因为这有助于理解,而且语言也很多具有两种可用的实现(主要在功能语言领域,请参见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一样,在运行时优化了机器代码。


2
好了,这意味着,一个Python脚本首先编译为字节码,然后将其通过像CPython的,Jython或IronPython的等解释器执行
的Pankaj Upadhyay

19
不,它将被编译为字节码,然后由相应的VM执行字节码。CPython既是编译器又是VM,但是Jython和IronPython只是编译器。
伊格纳西奥·巴斯克斯

1
@Igacio:我对IronPython / Jython没有太多经验,但是至少Jython不会提供类似解释器的层吗?我认为尝试将Python转换为静态类型的JVM字节码是不可行的。不过,关于编译器和解释器属于同一包的一部分,这是个好主意。

2
+1“ ...实现的属性”。我本人会说“它允许交互式外壳”
Jesvin Jose 2011年

2
@delnan:好吧,Jython确实充当了Python语言和Java VM之间的一种中介,但是它确实可以编译为Java字节码。
伊格纳西奥·巴斯克斯

34

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

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


11
我喜欢“需要另一个程序来运行它”的观点。那有助于澄清我的一些想法。
马特

所以python.exe首先优化代码,然后对其进行解释?
Koray Tugay 2015年

@KorayTugay,当为python.exe提供人类可读的文本源代码时,它首先生成优化的字节码,然后对其进行解释(如您所说);但是,如果已经有一个字节代码文件(已预编译),则不必执行第一步,这样可以节省一些时间。
GordonBGood

31

答案取决于正在使用哪种python实现。如果使用的是CPython(Python的标准实现)或Jython(目标是与Java编程语言集成),则首先将其翻译为bytecode,然后根据所使用的python的实现,将此bycode定向到相应的用于解释的虚拟机。用于CPython的PVM(Python虚拟机)和用于Jython的JVM(Java虚拟机)。

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


在将字节码转换为字节码的过程中,确实需要哪个编译器?
RICKY

Pypy是Python实现,而不是“ CPython”实现。实际上,Pypy是CPython的替代品(pypy.org/features.html)。
乔治

13

根据Python的官方网站,它是一种解释语言。

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

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

...

由于没有编译步骤...

...

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

...

相反,当解释器发现错误时,它将引发异常。当程序未捕获异常时,解释器将打印堆栈跟踪。


7

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

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

首先,我想告诉您,如果您来自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解释器,一些则使用即时编译器。参考:点击这里

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


6

如果(您知道Java){

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

}其他{

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

}


2

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


1

对于新手

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

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

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


0

您编写的python代码将编译为python字节码,从而创建扩展名为.pyc的文件。如果进行编译,那么又一个问题是,为什么不编译语言。

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

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


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.