Python是一种解释性语言。但是为什么我的源目录包含。pyc文件,这些文件被Windows识别为“编译过的Python文件”?


当前回答

Python(至少是它最常见的实现)遵循将原始源代码编译为字节码的模式,然后在虚拟机上解释字节码。这意味着(同样,最常见的实现)既不是纯解释器也不是纯编译器。

然而,另一方面,编译过程基本上是隐藏的——.pyc文件基本上被视为缓存;它们能加快速度,但你通常根本不需要注意到它们。它在必要时根据文件时间/日期戳自动使它们失效并重新加载(重新编译源代码)。

我所见过的唯一一次问题是,编译后的字节码文件以某种方式获得了未来的时间戳,这意味着它看起来总是比源文件更新。因为它看起来更新,源文件从来没有重新编译过,所以无论你做了什么更改,它们都被忽略了…

其他回答

它们包含字节代码,Python解释器将源代码编译为字节代码。这段代码随后由Python的虚拟机执行。

Python的文档是这样解释定义的:

Python是一种解释性语言,例如 而不是编译的 区别可能是模糊的,因为 字节码编译器的存在。 这意味着源文件可以 直接运行而不显式地运行 创建一个可执行文件,然后 运行。

Python(至少是它最常见的实现)遵循将原始源代码编译为字节码的模式,然后在虚拟机上解释字节码。这意味着(同样,最常见的实现)既不是纯解释器也不是纯编译器。

然而,另一方面,编译过程基本上是隐藏的——.pyc文件基本上被视为缓存;它们能加快速度,但你通常根本不需要注意到它们。它在必要时根据文件时间/日期戳自动使它们失效并重新加载(重新编译源代码)。

我所见过的唯一一次问题是,编译后的字节码文件以某种方式获得了未来的时间戳,这意味着它看起来总是比源文件更新。因为它看起来更新,源文件从来没有重新编译过,所以无论你做了什么更改,它们都被忽略了…

没有解释性语言这种东西。使用解释器还是编译器纯粹是实现的特性,与语言完全无关。

每种语言都可以由解释器或编译器实现。绝大多数语言都至少有每种类型的一个实现。(例如,C和c++有解释器,JavaScript、PHP、Perl、Python和Ruby有编译器。)此外,大多数现代语言实现实际上结合了解释器和编译器(甚至多个编译器)。

A language is just a set of abstract mathematical rules. An interpreter is one of several concrete implementation strategies for a language. Those two live on completely different abstraction levels. If English were a typed language, the term "interpreted language" would be a type error. The statement "Python is an interpreted language" is not just false (because being false would imply that the statement even makes sense, even if it is wrong), it just plain doesn't make sense, because a language can never be defined as "interpreted."

特别是,如果你看一下当前现有的Python实现,这些是他们正在使用的实现策略:

IronPython: compiles to DLR trees which the DLR then compiles to CIL bytecode. What happens to the CIL bytecode depends upon which CLI VES you are running on, but Microsoft .NET, GNU Portable.NET and Novell Mono will eventually compile it to native machine code. Jython: interprets Python sourcecode until it identifies the hot code paths, which it then compiles to JVML bytecode. What happens to the JVML bytecode depends upon which JVM you are running on. Maxine will directly compile it to un-optimized native code until it identifies the hot code paths, which it then recompiles to optimized native code. HotSpot will first interpret the JVML bytecode and then eventually compile the hot code paths to optimized machine code. PyPy: compiles to PyPy bytecode, which then gets interpreted by the PyPy VM until it identifies the hot code paths which it then compiles into native code, JVML bytecode or CIL bytecode depending on which platform you are running on. CPython: compiles to CPython bytecode which it then interprets. Stackless Python: compiles to CPython bytecode which it then interprets. Unladen Swallow: compiles to CPython bytecode which it then interprets until it identifies the hot code paths which it then compiles to LLVM IR which the LLVM compiler then compiles to native machine code. Cython: compiles Python code to portable C code, which is then compiled with a standard C compiler Nuitka: compiles Python code to machine-dependent C++ code, which is then compiled with a standard C compiler

您可能会注意到,该列表中的每一个实现(加上我没有提到的其他一些实现,如tinypy、Shedskin或Psyco)都有一个编译器。事实上,据我所知,目前还没有纯解释的Python实现,没有这样的实现计划,也从来没有这样的实现。

不仅术语“解释语言”没有意义,即使你将其理解为“带有解释实现的语言”,这显然是不正确的。不管是谁告诉你的,显然他不知道自己在说什么。

特别是,您看到的.pyc文件是由CPython、Stackless Python或Unladen Swallow生成的缓存字节码文件。

这是为初学者准备的,

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

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

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

如果你需要为一个未导入的模块创建一个.pyc文件,你可以使用py_compile和compileall模块。

py_compile模块可以手动编译任何模块。一种方法是交互式地使用该模块中的py_compile.compile函数:

>>> import py_compile
>>> py_compile.compile('abc.py')

这将把.pyc写到与abc.py相同的位置(你可以用可选参数cfile重写它)。

您还可以使用compileall模块自动编译一个或多个目录中的所有文件。

python -m compileall

如果省略目录名(本例中的当前目录),模块将编译sys.path上的所有内容

为了加速加载模块,Python将模块的编译内容缓存在.pyc中。

CPython将源代码编译为“字节码”,出于性能考虑,当源文件发生更改时,CPython会将此字节码缓存到文件系统中。这使得Python模块的加载速度更快,因为可以绕过编译阶段。当你的源文件是foo.py时,CPython将字节代码缓存在foo.py文件中。Pyc文件就在源代码旁边。

在python3中,Python的导入机制被扩展为在每个Python包目录中的单个目录中写入和搜索字节码缓存文件。这个目录将被称为__pycache__。

下面是一个描述如何加载模块的流程图:

欲了解更多信息:

裁判:PEP3147 参考:“编译”的Python文件