根据我的理解:

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

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

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

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


当前回答

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

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

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

注:

计算机系统的模拟

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

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

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

其他回答

如果(你懂Java) { Python代码像java一样被转换成字节码。 每次您尝试访问该字节码时,都会再次执行它。 }其他{ Python代码最初被翻译成一种叫做字节码的东西 接近机器语言,但不是真正的机器代码 因此,每次我们访问或运行它时,字节码都会再次执行 }

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

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

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

注:

计算机系统的模拟

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

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

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

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

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

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

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

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

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

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

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

Let's summarize what happens behind the scenes. When Python executes a program, Python reads the .py into memory, and parses it in order to get a bytecode, then goes on to execute. For each module that is imported by the program, Python first checks to see whether there is a precompiled bytecode version, in a .pyo or .pyc, that has a timestamp which corresponds to its .py file. Python uses the bytecode version if any. Otherwise, it parses the module's .py file, saves it into a .pyc file, and uses the bytecode it just created.

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

Python虚拟机(PVM)

Once our program has been compiled into byte code, it is shipped off for execution to Python Virtual Machine (PVM). The PVM is not a separate program. It need not be installed by itself. Actually, the PVM is just a big loop that iterates through our byte code instruction, one by one, to carry out their operations. The PVM is the runtime engine of Python. It's always present as part of the Python system. It's the component that truly runs our scripts. Technically it's just the last step of what is called the Python interpreter.

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

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

首先我想说的是,如果你来自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。

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

Having an intermediate code (like bytecode) i believe doesnt make difference to categorize it overall as compiler. Though this component (intermediate code generation) is typically been part of compiler but it can also be used in interpreters. See wiki definition of interpreter https://en.m.wikipedia.org/wiki/Interpreter_(computing). Its a crucial piece to add efficiency in terms of execution speed. With cache its even more powerful so that if you havent changed code in current program scope you skip heavy processing steps like lexical, semantic analysis and even some of code optimization.