只是想知道(既然我已经从需要编译器的C ++开始),为什么Python不需要编译器?
我只需输入代码,将其另存为exec,然后运行即可。在C ++中,我必须进行构建以及所有其他有趣的东西。
python
命令来解释.py文件,或者,如果您使用IDLE或Eclipse,则IDE会为您执行。
只是想知道(既然我已经从需要编译器的C ++开始),为什么Python不需要编译器?
我只需输入代码,将其另存为exec,然后运行即可。在C ++中,我必须进行构建以及所有其他有趣的东西。
python
命令来解释.py文件,或者,如果您使用IDLE或Eclipse,则IDE会为您执行。
Answers:
Python有一个编译器!您只是没有注意到它,因为它会自动运行。但是,您可以知道它在那里:查看为您的模块生成的.pyc
(或.pyo
是否已打开优化器)文件import
。
另外,它不会编译为本机计算机的代码。而是将其编译为虚拟机使用的字节码。虚拟机本身就是一个编译程序。这与Java的工作原理非常相似。实际上非常相似,实际上有一个Python变体(Jython)可以编译为Java虚拟机的字节码!还有IronPython,可编译为Microsoft的CLR(由.NET使用)。(普通的Python字节码编译器有时也称为CPython,以使它们与这些替代方案毫无歧义。)
C ++需要公开其编译过程,因为该语言本身并不完整。它没有指定链接器构建程序所需了解的所有内容,也没有可移植地指定编译选项(某些编译器允许您使用#pragma
,但这不是标准的)。因此,您必须使用makefiles以及自动地狱(autoconf / automake / libtool)完成其余工作。这实际上只是C语言所做的保留。C之所以这样做,是因为它使编译器变得简单,这是它如此流行的一个主要原因(任何人都可以在80年代开发出一个简单的C编译器)。
一些可能影响编译器或链接器操作但在C或C ++语法中未指定的东西:
其中一些可以被检测到,但无法指定。例如,我可以检测到正在使用哪个C ++ __cplusplus
,但是我无法在代码本身中指定C ++ 98是用于我的代码的那个。我必须将其作为标志传递给Makefile中的编译器,或者在对话框中进行设置。
虽然您可能会认为编译器中存在一个“依赖关系解决方案”系统,该系统会自动生成依赖关系记录,但这些记录仅说明给定源文件使用哪些头文件。它们无法指示链接到可执行程序所需的其他附加源代码模块,因为在C或C ++中没有标准的方法来指示给定的头文件是另一个源代码模块的接口定义,而不是仅仅一堆。您希望在多个地方显示的行,因此您不会重复自己。文件命名约定中有一些传统,但是编译器和链接器不知道或不执行这些传统。
可以使用设置其中几个#pragma
,但这不是标准的,我所说的是标准。所有这些东西都可以由一个标准指定,但并不是为了向后兼容。普遍的看法是,makefile和IDE不会损坏,因此请不要修复它们。
Python用语言来处理所有这些。例如,import
指定显式的模块依赖关系,表示依赖关系树,并且模块不拆分为头文件和源文件(即接口和实现)。
Python是一种解释型语言。这意味着您的计算机上存在可以读取Python代码并将“指令”发送到计算机的软件。在上解释语言维基百科文章可能会感兴趣。
编译诸如C ++(一种编译语言)之类的语言时,意味着将其转换为机器代码,以便在执行时直接由硬件读取。在上编译语言维基百科文章可能提供一个有趣的对比。
并非所有的编译语言都有一个面对面的edit-compile-link-run循环。
您遇到的是C ++的功能/局限性(或至少是C ++的实现)。
要执行任何操作,您必须将代码存储到文件中,并通过称为链接的过程构建整体图像。
特别是,这种整体式链接过程被误认为是编译和解释之间的区别。
有些语言通过消除笨拙的整体链接步骤,而不是通过消除对机器代码的编译,来更加动态地完成所有这些工作。源代码仍被编译为目标文件,但它们被加载到运行时映像中,而不是链接到整体可执行文件中。
您说“重新加载此模块”,然后它会加载源代码并对其进行解释或编译,具体取决于某些模式切换。
即使您使用的是C语言,Linux内核编程也具有这种风格。您可以重新编译模块并进行加载和卸载。当然,您仍然知道您正在生成一些可执行的东西,并且它由复杂的构建系统管理,还需要一些手动步骤。但是事实是,最后您可以卸载和重新加载那个小模块,而不必重新启动整个内核。
某些语言的模块化程度甚至更高,并且构建和加载均在其运行时完成,因此更加无缝。
所有编程语言都需要将人的概念转换为目标机器代码。甚至汇编语言也必须翻译成机器代码。该翻译通常在以下阶段进行:
阶段1:分析和转换(解析)为中间代码。阶段2:使用占位符将外部代码转换为目标机器代码。阶段3:解析外部引用并将其打包到机器可执行程序中。
这种转换通常称为预编译和“及时”(JIT)或运行时编译。
诸如C,C ++,COBOL,Fortran,Pascal(并非全部)和Assembly之类的语言是预编译的语言,可以由操作系统直接执行而无需解释器。
诸如Java,BASIC,C#和Python之类的语言将被解释。他们都使用在阶段1中创建的中间代码,但是有时将它们转换为机器代码的方式有所不同。最简单的形式使用该中间代码来执行可以完成预期工作的机器代码例程。其他人则将中间代码编译为机器代码,并在运行时进行外部依赖关系修复。编译后即可立即执行。同样,机器代码存储在先前编译的可重用机器代码的缓存中,如果以后需要再次使用该功能,则以后可以重用。如果一个函数已经被缓存,则解释器不需要再次编译它。
大多数现代高级语言都属于解释型(使用JIT)类别。预编译的大多是较旧的语言,例如C&C ++。