Answers:
据我所知,您不能在没有修改的情况下在每台机器上(例如Windows或Linux上)执行Python程序(编译为字节码)。
你不对 python字节码是跨平台的。请参阅python字节码版本相关吗?是否依赖平台?在堆栈溢出。但是,它在各个版本之间不兼容。Python 2.6无法执行Python 2.5文件。因此,尽管是跨平台的,但它通常不适合用作分发格式。
但是为什么Python同时需要编译器和解释器?
速度。严格的解释很慢。实际上,每种“解释”语言实际上都将源代码编译成某种内部表示形式,因此不必重复解析代码。在python的情况下,它将内部表示形式保存到磁盘,以便下次需要代码时可以跳过解析/编译过程。
我可以理解Java需要编译器和解释器的事实。
没有。Java语言规范中没有任何内容表明Java需要具有编译器。Java语言规范中也没有任何内容表明Java需要具有解释器。
究竟是使用解释器,编译器还是两者的组合,完全由实现者决定。
实际上,有一些 Java的实现可以直接编译为机器代码,例如GNU Compiler for Java gcj
。从技术上讲,Oracle OpenJDK Java编译器还可以编译为机器代码,尤其是JVM字节代码。现在,您可能会说,请稍等,这不是机器代码!但是,存在用于x86机器代码的软件解释器,并且存在可以执行JVM字节代码的硬件CPU,那么,什么使一个“本机”变成另一个“本机”?
注意,JVM字节代码位于Java语言规范之外,就像x86机器代码一样。
然后虚拟机(在Windows,Linux,Android等上)将字节码转换为当前架构的机器码。
同样,这完全取决于实现者。
原始的Sun JVM从不翻译,而是始终进行解释。当前的Oracle OpenJDK JVM进行解释,并且仅编译那些经常执行的部分。Maxine Research VM总是JIT编译。Excelsior.JET实现会提前编译一次。IKVM.NET JVM编译为CIL字节码。Android运行时会在安装过程中提前一次编译。(此外,Android运行时不理解JVM字节码,它使用Dalvik字节码,这是一种完全不同的语言。)
但是,为什么Python同时需要编译器和解释器?
再一次,事实并非如此。Python语言规范中没有任何内容表明Python需要具有编译器。Python语言规范中也没有任何内容表明Python需要避开解释器。
请注意,实际上,永远不会解释Python 。所有现有的 Python实现总是将 Python编译为其他语言。然后,该语言可能会也可能不会被解释,但是该语言与Python是不同的语言。Python不会被解释。
为什么不仅仅使用解释?
因为Python并不是为了易于机器解释而设计的。它被设计为易于人类解释。OTOH,CPython的字节码,被设计用于机器很容易解释。因此,用一种为人类设计的语言编写代码并以一种为机器设计的语言进行解释是有意义的,为了相互之间的相互影响,您必须进行编译。
据我所知,未经修改,您将无法在任何Windows或Linux计算机上执行Python程序(编译为字节码)。
是的你可以。CPython VM适用于Windows和Linux,PyPy,Jython和IronPython也适用。
语言不必编译或解释。语言只是有。实际上,无需任何解释器或编译器,语言就可以完美存在!例如,他在1930年代设计的Konrad Zuse的Plankalkül在他一生中从未实现。您仍然可以在其中编写程序,可以分析这些程序,对它们进行推理,证明其属性……您只是无法执行它们。(嗯,实际上,那是错误的:您当然可以用脑袋或纸和笔将它们运行。)
现在,语言的任何特定实现都可以使用编译器(甚至多个编译器),解释器或任何组合。但是,这是一个特点实现,而不是语言。每种语言都可以用编译器实现,每种语言都可以用解释器实现。
但是请注意,没有解释器就无法运行程序。编译器只是将程序从一种语言翻译成另一种语言。就是这样。现在,您拥有相同的程序,只是使用不同的语言。实际获得程序结果的唯一方法是对其进行解释。有时,该语言是一种非常简单的二进制机器语言,而解释器实际上是用硅胶硬编码的(我们称其为“ CPU”),但这仍然是解释。
您可能也对我的这个答案感兴趣,该答案解释了组合解释器,JIT编译器和AOT编译器的区别和不同方法,并且此答案涉及AOT编译器和JIT编译器之间的区别。
确实,字节码不适合作为分发格式,但这并不意味着它没有用。除了缩短给定机器的启动时间外,在首次运行后,解释字节码也比解释AST或逐行解释(比我所禁止的)简单得多。
字节码是代码的一种更底层,更常规,更紧凑的表示(从语义上和就内存布局而言)。操作顺序已经阐明,局部变量名称已解析为更简单的形式(整数索引)。无需遵循复杂的语法,只需一个简单的指令即可。此外,所需的状态更少:对于逐行解释,您基本上需要保留整个解析器,并且AST解释器会因树遍历而炸毁调用堆栈,而字节码解释器只需要一个小的堆栈即可获取临时值和当地人。
这些因素和其他因素共同导致字节码解释器比其他解释器快得多。