个性化阅读
专注于IT技术分析

为什么有那么多Python? Python实现比较

本文概述

Python很棒。

令人惊讶的是, 这是一个相当含糊的陈述。 ” Python”是什么意思?我是说Python是抽象接口吗?我的意思是CPython, 它是通用的Python实现(不要与类似名称的Cython混淆)吗?还是我完全是其他意思?也许我是指Jython, IronPython或PyPy。也许我真的已经走出了深渊, 而我正在谈论RPython或RubyPython(这是非常不同的东西)。

虽然上面提到的技术是通用名称和通用引用的, 但是其中一些功能完全不同的目的(或者至少以完全不同的方式运行)。

在使用Python界面的整个过程中, 我经常使用大量的。* ython工具。但是直到最近, 我才花时间了解它们的含义, 它们的工作原理以及为什么需要它们(以自己的方式)。

在本教程中, 我将从头开始, 逐步介绍各种Python实现, 最后对PyPy进行全面介绍, 我相信这是该语言的未来。

一切始于对” Python”实际上是什么的理解。

如果你对机器代码, 虚拟机等有很好的了解, 请随时跳过。

” Python是解释还是编译的?”

这是Python初学者的普遍困惑。

进行比较时首先要意识到的是” Python”是一个接口。有关于Python应该做什么以及应该如何工作的规范(与任何接口一样)。并且有多种实现方式(与任何接口一样)。

要意识到的第二件事是, “解释”和”编译”是实现的属性, 而不是接口。

因此, 问题本身的格式并不正确。

是Python解释还是编译?这个问题的格式不是真的。

就是说, 对于最常见的Python实现(CPython:用C编写, 通常简称为” Python”, 如果你不知道我在说什么, 那么肯定会使用什么), 答案是:解释, 并进行了一些编译。 CPython将Python源代码编译为字节码, 然后解释该字节码, 并立即执行。

*注意:这不是传统意义上的”编译”。通常, 我们会说”编译”是一种高级语言, 并将其转换为机器代码。但这是一种”编译”。

让我们更仔细地看一下这个答案, 因为它将帮助我们理解本文后面的一些概念。

字节码与机器码

了解字节码与机器码(又称本机码)之间的区别非常重要, 也许可以通过示例来最好地说明一下:

  • C编译为机器代码, 然后直接在你的处理器上运行。每条指令都指示你的CPU移动内容。
  • Java编译为字节码, 然后在Java虚拟机(JVM)上运行, 这是执行程序的计算机的抽象。然后, 每条指令都由与计算机交互的JVM处理。

简而言之:机器代码要快得多, 但字节码则更可移植且更安全。

机器代码根据你的机器而有所不同, 但字节码在所有机器上看起来都相同。可能有人会说, 机器代码已针对你的设置进行了优化。

返回到CPython实现, 工具链过程如下:

  1. CPython将你的Python源代码编译为字节码。
  2. 然后, 该字节码在CPython虚拟机上执行。

初学者经常认为Python是因为.pyc文件而编译的。有一个事实:.pyc文件是编译后的字节码, 然后将其解释。因此, 如果你之前已经运行过Python代码并拥有.pyc文件, 那么它第二次运行会更快, 因为它不必重新编译字节码。

备用VM:Jython, IronPython等

如前所述, Python有几种实现。再次, 如前所述, 最常见的是CPython, 但是出于比较指南的考虑, 还有其他一些应该提及。这是一个用C语言编写的Python实现, 被视为”默认”实现。

但是其他Python实现又如何呢? Jython是最著名的应用程序之一, 它是使用JVM编写的用Java编写的Python实现。虽然CPython生成可在CPython VM上运行的字节码, 但Jython生成可在JVM上运行的Java字节码(这与编译Java程序时生成的东西相同)。

在此Python实现图中描述了Jython对Java字节码的使用。

你可能会问:”为什么要使用替代实现?”。好吧, 其中一个是, 这些不同的Python实现可与不同的技术堆栈很好地配合使用。

CPython使得为Python代码编写C扩展变得非常容易, 因为最后它是由C解释器执行的。另一方面, Jython使使用其他Java程序变得非常容易:你可以毫不费力地导入任何Java类, 从Jython程序中调用并利用Java类。 (此外:如果你还没有仔细考虑过, 这实际上是很疯狂的。我们现在可以混合和混合不同的语言, 并将它们编译成相同的内容。(如Rostin所述, 混合使用Fortran和C代码已经有一段时间了, 因此, 这当然不一定是新的。但这仍然很酷。

例如, 这是有效的Jython代码:

[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_51
>>> from java.util import HashSet
>>> s = HashSet(5)
>>> s.add("Foo")
>>> s.add("Bar")
>>> s
[Foo, Bar]

IronPython是另一种流行的Python实现, 完全用C#编写并且针对.NET堆栈。特别是, 它可以在你可以称为.NET虚拟机(Microsoft的通用语言运行时, CLR)上运行, 与JVM相当。

你可能会说Jython:Java :: IronPython:C#。它们在相同的VM上运行, 你可以从IronPython代码导入C#类, 从Jython代码导入Java类, 等等。

无需接触非CPython Python实现, 就可以生存。但是切换有很多好处, 其中大部分取决于你的技术堆栈。使用很多基于JVM的语言? Jython可能适合你。关于.NET堆栈?也许你应该尝试IronPython(也许你已经拥有了)。

此Python比较表演示了Python实现之间的差异。

顺便说一句:虽然这不是使用其他实现的理由, 但请注意, 这些实现实际上在行为上有所不同, 除了对待Python源代码的方式不同。但是, 这些差异通常很小, 随着这些实现的积极开发, 它们会随着时间的流逝而消失或消失。例如, IronPython默认使用Unicode字符串。但是, 对于版本2.x, CPython默认为ASCII(对于非ASCII字符, 默认为UnicodeEncodeError), 但是对于3.x, 默认情况下确实支持Unicode字符串。

即时编译:PyPy和未来

因此, 我们有一个用C编写的Python实现, 一个用Java编写, 一个用C#编写。接下来的逻辑步骤:用Python编写的Python实现。 (受过良好教育的读者会注意到这有点误导。)

这可能会使你感到困惑。首先, 让我们讨论即时(JIT)编译。

JIT:为什么和如何

回想一下, 本机代码比字节码快得多。好吧, 如果我们可以编译一些字节码然后作为本机代码运行呢?我们必须付出一些代价才能编译字节码(即时间), 但是如果最终结果更快, 那就太好了!这就是JIT编译的动机, 它是一种混合技术, 将解释器和编译器的优点融合在一起。从根本上讲, JIT希望利用编译来加快解释系统的速度。

例如, JIT采取的常见方法是:

  1. 标识经常执行的字节码。
  2. 将其编译为本机代码。
  3. 缓存结果。
  4. 无论何时设置要运行相同的字节码, 都应获取预先编译的机器代码并获得好处(即提高速度)。

这就是PyPy实现的全部内容:将JIT引入Python(有关以前的工作, 请参阅附录)。当然, 还有其他目标:PyPy的目标是成为跨平台的, 轻巧的存储和无栈支持。但是JIT确实是它的卖点。作为一系列时间测试的平均值, 据说可以将性能提高6.27倍。有关详细信息, 请参阅PyPy Speed Center的以下图表:

使用PyPy实现将JIT引入Python界面可带来性能提升。

PyPy很难理解

PyPy具有巨大的潜力, 并且目前与CPython高度兼容(因此它可以运行Flask, Django等)。

但是关于PyPy却有很多困惑(例如, 请参阅有关创建PyPyPy的荒​​谬建议……)。我认为这主要是因为PyPy实际上是两件事:

用RPython编写的Python解释器(不是Python(我之前说谎))。 RPython是具有静态类型的Python的子集。在Python中, 对类型进行严格推理是”几乎不可能的”(为什么这么难?请考虑以下事实:

 x = random.choice([1, "foo"])

将是有效的Python代码(贷给Ademan)。 x是什么类型?如果不严格执行变量类型, 我们又该如何推断呢?)使用RPython, 你牺牲了一些灵活性, 但是却使推理内存管理和其他事情变得非常容易, 这可以进行优化。

编译器可为各种目标编译RPython代码并添加JIT。默认平台是C, 即RPython-to-C编译器, 但你也可以将JVM和其他平台作为目标。

仅在本Python比较指南中为清楚起见, 我将它们称为PyPy(1)和PyPy(2)。

你为什么需要这两件事, 为什么要在同一屋檐下?这样想:PyPy(1)是用RPython编写的解释器。因此, 它接受用户的Python代码并将其编译为字节码。但是解释器本身(用RPython编写)必须由另一个Python实现来解释才能运行, 对吗?

好吧, 我们可以只使用CPython运行解释器。但这不会很快。

相反, 我们的想法是, 我们使用PyPy(2)(称为RPython工具链)将PyPy的解释器编译为用于在我们的计算机上运行的另一个平台(例如C, JVM或CLI)的代码, 并在JIT中添加好。神奇:PyPy将JIT动态添加到解释器中, 从而生成自己的编译器! (同样, 这很疯狂:我们正在编译解释器, 并添加了另一个单独的独立编译器。)

最后, 结果是一个独立的可执行文件, 可解释Python源代码并利用JIT优化。这正是我们想要的!一口气, 但也许这张图会有所帮助:

该图说明了PyPy实现的优点,包括解释器,编译器和带有JIT的可执行文件。

重申一下, PyPy的真正优点在于, 我们可以在RPython中为自己编写许多不同的Python解释器, 而不必担心JIT。然后, PyPy将使用RPython工具链/ PyPy(2)为我们实现JIT。

实际上, 如果我们变得更加抽象, 则理论上你可以为任何一种语言编写解释器, 将其提供给PyPy, 并获得该语言的JIT。这是因为PyPy专注于优化实际的解释器, 而不是其解释语言的细节。

从理论上讲, 你可以为任何一种语言编写解释器, 将其提供给PyPy, 然后获得该语言的JIT。

作为简短的题外话, 我想提到JIT本身绝对令人着迷。它使用一种称为跟踪的技术, 该技术执行如下:

  1. 运行解释器并解释所有内容(不添加JIT)。
  2. 对解释的代码进行一些简要的分析。
  3. 确定你之前执行的操作。
  4. 将这些代码位编译为机器代码。

欲了解更多, 这篇论文是高度可访问的并且非常有趣。

总结一下:我们使用PyPy的RPython-to-C(或其他目标平台)编译器来编译PyPy的RPython实现的解释器。

本文总结

在对Python实现进行长时间的比较之后, 我不得不问自己:为什么这么好?为什么这个疯狂的想法值得追求?我认为Alex Gaynor在他的博客上说得很好:” [PyPy是未来”, 因为[它]提供了更快的速度, 更多的灵活性, 并且是Python成长的更好的平台。”

简而言之:

  • 快速, 因为它可以将源代码编译为本地代码(使用JIT)。
  • 它非常灵活, 因为它只需很少的额外工作即可将JIT添加到你的口译员。
  • 灵活(再次)是因为你可以用RPython编写解释器, 比C语言更容易扩展(事实上, 它很容易, 有一个编写你自己的解释器的教程)。

附录:你可能听说过的其他Python名称

  • Python 3000(Py3k):Python 3.0的替代命名, 它是一个主要的, 向后不兼容的Python发行版, 于2008年问世。Py3k团队预测, 要完全采用此新版本大约需要五年的时间。尽管大多数(警告:轶事声称)Python开发人员继续使用Python 2.x, 但人们越来越意识到Py3k。

  • Cython:Python的超集, 包含用于调用C函数的绑定。
    • 目标:允许你为Python代码编写C扩展。
    • 还可以让你向现有的Python代码添加静态类型, 从而可以对其进行编译并达到类似C的性能。
    • 这类似于PyPy, 但不相同。在这种情况下, 你必须在将用户代码传递给编译器之前强制输入。使用PyPy, 你可以编写普通的旧Python, 并且编译器可以处理所有优化。

  • Numba:”即时专业编译器”, 它将JIT添加到带注释的Python代码中。用最基本的术语来说, 你可以给它一些提示, 并且可以加快代码的速度。 Numba是Anaconda发行版的一部分, Anaconda发行版是一组用于数据分析和管理的软件包。

  • IPython:与讨论的其他内容完全不同。 Python的计算环境。与GUI工具包和浏览器体验等交互可交互

  • Psyco:Python扩展模块, 是Python JIT的早期尝试之一。但是, 此后被标记为”未维护且已死亡”。实际上, Psyco的首席开发人员Armin Rigo现在正在研究PyPy。

Python语言绑定

  • RubyPython:Ruby和Python VM之间的桥梁。允许你将Python代码嵌入到Ruby代码中。你定义Python的开始和停止位置, 然后RubyPython在虚拟机之间封送数据。

  • PyObjc:Python和Objective-C之间的语言绑定, 充当它们之间的桥梁。实际上, 这意味着你可以利用Python代码中的Objective-C库(包括创建OS X应用程序所需的一切)以及Objective-C代码中的Python模块。在这种情况下, 使用C(这是Objective-C的子集)编写CPython很方便。

  • PyQt:PyObjc为你提供OS X GUI组件的绑定, 而PyQt对Qt应用程序框架也具有相同的功能, 使你可以创建丰富的图形界面, 访问SQL数据库等。另一个旨在将Python的简单性引入其他框架的工具。

JavaScript框架

  • pyjs(Pyjamas):用于在Python中创建Web和桌面应用程序的框架。包括Python到JavaScript的编译器, 小部件集和其他一些工具。

  • Brython:用JavaScript编写的Python VM, 允许在浏览器中执行Py3k代码。

赞(0)
未经允许不得转载:srcmini » 为什么有那么多Python? Python实现比较

评论 抢沙发

评论前必须登录!