【问题标题】:Are Python modules compiled?Python 模块是否已编译?
【发布时间】:2017-02-04 23:40:26
【问题描述】:

试图了解python库是否被编译,因为我想知道我编写的解释代码是否会执行相同或更差。

例如我在某处看到它提到 numpy 和 scipy 是有效的,因为它们是编译的。我不认为这意味着编译的字节码那么这是如何完成的?它是使用 cython 之类的东西编译成 c 的吗?还是它是使用类似 c 的语言编写并以兼容的方式编译的?

这适用于所有模块还是根据具体情况?

【问题讨论】:

    标签: python numpy compilation


    【解决方案1】:

    NumPy 和其他几个库是用 C 和其他语言(如 FORTRAN)编写的代码的部分包装器,编译后运行速度比 Python 快。这有助于避免 Python 中的循环、指针间接和每元素动态类型检查的成本。这在this question 中有解释:

    Numpy 数组是同构类型的密集排列的数组。相比之下,Python 列表是指向对象的指针数组,即使它们都属于同一类型。因此,您可以获得参考位置的好处。

    此外,许多 Numpy 操作是在 C 中实现的,避免了 Python 中循环、指针间接和每个元素的动态类型检查的一般成本。速度提升取决于您正在执行的操作,但几个数量级在数字运算程序中并不少见。

    编译为字节码(.pyc 文件)的 Python 代码是一个单独的主题,其中编译 Python 脚本以提高启动性能(请参阅this question)。

    【讨论】:

    • Riiight,所以这取决于具体的库以及它是如何构建的。理论上,如果我想创建自己的高效 Python 库,我可以用另一种语言构建它,然后为它编写一个包装器,正如你所提到的。您是否知道“广泛使用”的python库是否是这样编写的?我该如何检查?
    • 如果您查看Install docs for NumPy,您可以看到许多 NumPy 模块需要 C 或 FORTRAN 编译器。 AFAIK 许多科学和数学库使用较低级别的语言,包括很多 SciPy 堆栈。
    【解决方案2】:

    Python 可以执行用 Python 编写的函数(解释)和编译的函数。有关于编写与 Python 集成的代码的完整 API 文档。 cython 是执行此操作的更简单工具之一。

    库可以是任意组合 - 纯 Python、Python 加上编译代码的接口,或者全部编译。解释文件以.py 结尾,编译后的文件通常是.so.dll(取决于操作系统)。安装纯 Python 代码很容易——只需加载、解压缩(如果需要)并放置正确的目录。混合代码需要一个编译步骤(因此需要一个 c 编译器等),或者下载带有二进制文件的版本。

    通常情况下,开发人员会在 Python 中编写代码,然后在 c 中重写对速度敏感的部分。或者他们找到一些外部库的工作 cFortran 代码,并链接到那个。

    numpyscipy 混合使用。他们有很多 Python 代码、核心编译部分,并使用外部库。而c 代码可能非常难以阅读。

    作为numpy 用户,您应该首先尝试使用 Python 代码获得尽可能高的清晰度和性能。大多数优化 SO 问题都讨论了使用 numpy 的已编译功能的方法 - 所有在整个数组上工作的操作。只有当您无法用高效的 numpy 代码表达您的操作时,您才需要使用像 cythonnumba 这样的工具。

    一般来说,如果您必须进行大量迭代,那么您使用的是低级操作。要么用数组操作替换循环,要么用 cython 重写循环。

    【讨论】:

      【解决方案3】:

      低级编译语言和性能

      @hpaulj 和@jeevcat 的答案是正确的。

      但Python是否被编译的故事更复杂。

      首先,确实写得好的C++代码比写得好的 Python代码快得多。而且编译后的代码一般可以加快计算速度。

      但原因不是因为代码被编译,本身。这是因为这些编译语言通常也是低级语言,可以让您直接操作内存、避免垃圾收集等。此外,允许 Python 动态性简单性,一切都是对象。因此,例如,Python 列表是一个对象,其中包含对“分散”在整个内存中的其他对象的引用列表。这(显然)比列表中所有值彼此相邻的内存块的计算效率低。

      而且,正如其他人所提到的,Python 代码只是调用(对话)这个其他更高效的 C 代码。

      Python 编译了吗?

      但是还有一个更有趣的问题。 Python 是否已编译?一些人可能会无意中声称它没有被编译。严格来说,这不是真的。任何时候您导入一个包或模块,如果它还没有被编译,它将被不可见地编译并保存。 (您可能甚至不会注意到任何编译发生。)

      您可以看到这种情况:任何.pyc 文件(以.pyc 而不是.py 结尾的文件)都是编译后的Python 文件。尝试在编辑器中或通过cat 打开.pyc 文件。你会看到它是一个二进制文件,看起来像乱码。

      看已编译 Python 代码的隐形创建

      如何创建编译好的 Python 代码?

      假设您有以下文件夹结构:

      ❯ tree -L 1
      .
      ├── __pypackages__ # This is a folder, the rest are files
      ├── addressbook.proto
      ├── addressbook_pb2.py
      ├── pdm.lock
      ├── protobuf-python-3.17.3.tar.gz
      ├── pyproject.toml
      └── readme.txt
      

      (以上结构包含 Python Google Protocol Buffer 示例,使用现代 PDM package manager 结构。)

      我们可以看到唯一的 Python 模块(文件)是 addressbook_pb2。所以,让我们导入那个文件:

      ❯ python
      Python 3.9.7 (default, Oct 13 2021, 06:45:31) 
      [Clang 13.0.0 (clang-1300.0.29.3)] on darwin
      Type "help", "copyright", "credits" or "license" for more information.
      >>> import addressbook_pb2
      >>>   [exit out of Python]
      ❯ 
      

      除了快速导入文件(模块)addressbook_pb2.py,我什么也没做。但只是这个简单的导入创建了一个名为__pycache__ 的完整“已编译代码文件夹”,其中包含已编译模块:

      ❯ tree -L 1
      .
      ├── __pypackages__
      ├── __pycache__ # This is the folder that was auto-generated
      ├── addressbook.proto
      ├── addressbook_pb2.py
      ├── pdm.lock
      ├── protobuf-python-3.17.3.tar.gz
      ├── pyproject.toml
      └── readme.txt
      

      现在我们来看看 __pycache__ 文件夹中有什么:

      ❯ ll __pycache__ # `ll` is my shortcut for `ls -al`, it's a common shortcut
      total 8
      drwxr-xr-x   3 mikewilliamson  staff    96B Oct 30 21:43 .
      drwxr-xr-x  34 mikewilliamson  staff   1.1K Oct 30 21:43 ..
      -rw-r--r--   1 mikewilliamson  staff   3.2K Oct 30 21:43 addressbook_pb2.cpython-39.pyc
      ❯ 
      

      请注意文件addressbook_pb2.cpython-39.pyc 在那里。词干是模块的名称 (addressbook_pb2)。但它也有 .cpython-39.pyc 扩展名。这告诉我们一些事情:

      1. 它是编译后的代码……这就是 .pyc 结尾的意思
      2. 它是使用cpython-39编译的,意思是它是Python(最普遍的)版本3.9的CPython“风味”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-29
        • 2023-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多