我们能否明确解释Python打包和导入的工作原理?

40 投票
4 回答
1376 浏览
提问于 2025-04-16 16:01

我在学习Python模块管理的过程中遇到了不少挑战。打包并不是人们每天都在做的事情,所以学习起来很麻烦,记起来也很费劲,尤其是你可能只在某个特定的时刻才会用到它。

我想在这里整理一个关于Python中导入、包管理和分发的全面概述,这样这个问题就能成为所有背后运作的魔法的最终解释。虽然我理解这个问题的大致方向,但这些内容是紧密相连的,任何单一的回答都无法解决主要问题:理解这一切是如何运作的,哪些是过时的,哪些是当前的,哪些只是完成同一任务的替代方案,还有哪些是特别之处。

以下是一些关键词供参考,但这只是其中的一部分。还有很多其他内容,欢迎大家补充更多细节。

  • PyPI
  • setuptools / Distribute
  • distutils
  • eggs
  • egg-link
  • pip
  • zipimport
  • site.py
  • site-packages
  • .pth文件
  • virtualenv
  • 处理在egg中的编译模块(使用和不使用easy_install安装)
  • 使用get_data()
  • pypm
  • bento
  • PEP 376
  • 奶酪商店
  • eggsecutable

链接到其他答案可能是个好主意。正如我所说,这个问题是为了提供一个高层次的概述。

4 个回答

2

我推荐一本关于Python的书,作者是Tarek Ziadek,你可以在这里找到。书里有一章专门讲如何打包和分发你的代码。

3

关于打包的问题,这里有个链接可以帮助你:http://guide.python-distribute.org/

至于导入模块,Fredrik Lundh 的一篇旧文章http://effbot.org/zone/import-confusion.htm依然是个很好的入门参考。

11

大体上,这段内容是想讨论Python的打包和分发方面,而不是具体的import机制。不幸的是,Python在打包方面提供了很多种方法,这让人有点困惑。我只是想先抛砖引玉,希望其他人能补充我遗漏的部分或指出我的错误。

首先,这里有一些术语比较混乱。包含__init__.py文件的目录被称为包。不过,我们这里讨论的主要是发布在PyPI(Python包索引)及其镜像网站上的特定版本的包,或者是在像Debian的Apt、Redhat的Yum、Fink、Macports、Homebrew或ActiveState的pypm这样的特定包管理系统中的包。

这些发布的包通常被称为“分发”,目的是将“包”这个词仅限于Python语言的构造。你可以在PEP-376中看到一些这样的用法。

接下来,你提到的关键词涉及Python生态系统的几个不同方面:

查找和发布Python分发:

  • PyPI(也叫奶酪商店)
  • PyPI镜像
  • 各种包管理工具/系统:apt、yum、fink、macports、homebrew
  • pypm(ActiveState的PyPI替代品)

以上这些都是提供发布Python分发的服务,格式各异。有些,比如PyPI镜像和apt/yum仓库,可以在你的本地机器或公司网络中运行,但人们通常使用官方的。大多数情况下,它们提供工具(在PyPI的情况下有多个工具)来帮助查找和下载分发。

用于创建和安装分发的库:

  • setuptools / Distribute
  • distutils

Distutils是Python包编译和构建成分发的标准基础设施。distutils有很多功能,但大多数人只知道:

from distutils.core import setup

setup(name='Distutils',
      version='1.0',
      description='Python Distribution Utilities',
      author='Greg Ward',
      author_email='gward@python.net',
      url='http://www.python.org/sigs/distutils-sig/',
      packages=['distutils', 'distutils.command'],
 )

在某种程度上,这就是你所需要的大部分内容。通过前面9行代码,你就有足够的信息来安装一个纯Python包,并且拥有发布该包到PyPI所需的最少元数据。

Setuptools提供了支持Egg格式及其所有特性的必要钩子。Distribute是Setuptools的一个替代品,增加了一些功能,同时尽量保持向后兼容。我相信Distribute将作为Distutils的继任者包含在Python 3中,替代from distutils.core import setup

Setuptools和Distribute都提供了distutils的自定义版本的设置命令,能够做一些有用的事情,比如支持Egg格式。

Python分发格式:

分发通常以源代码归档(tarball或zip文件)的形式提供。安装源分发的标准方法是下载并解压归档文件,然后运行里面的setup.py文件。

例如,以下命令将下载、构建并安装Pygments语法高亮库:

curl -O -G http://pypi.python.org/packages/source/P/Pygments/Pygments-1.4.tar.gz
tar -zxvf Pygments-1.4.tar.gz
cd Pygments-1.4
python setup.py build
sudo python setup.py install

另外,你也可以下载Egg文件并安装。通常通过使用easy_install或pip来完成:

sudo easy_install pygments
or 
sudo pip install pygments

Eggs的灵感来源于Java的Jar文件,它们有很多特性,你可以在这里了解更多。

Python包格式:

  • 未压缩的目录
  • zipimport(压缩的目录)

一个普通的Python包就是一个包含__init__.py文件的目录,里面可以有任意数量的额外模块或子包。Python还支持在*.zip文件中查找和加载源代码,只要这些文件被包含在PYTHONPATHsys.path)中。

安装Python包:

  • easy_install:最初的Egg安装工具,依赖于setuptools
  • pip:目前最流行的安装Python包的方法。类似于easy_install,但更灵活,具有一些很好的功能,比如需求文件,帮助记录依赖关系和重现部署。
  • pypmaptyum、fink等

环境管理/自动化部署:

  • bento
  • buildout
  • virtualenv(和virtualenvwrapper

以上工具用于帮助自动化和管理Python项目的依赖关系。基本上,它们提供工具来描述你的应用程序所需的分发,并自动安装这些特定版本的依赖。

包/分发的位置:

  • site-packages
  • PYTHONPATH
  • 当前工作目录(取决于你的操作系统和环境设置)

默认情况下,安装Python分发会将其放入site-packages目录。这个目录通常是/usr/lib/pythonX.Y/site-packages

找到你的site-packages目录的简单编程方法:

from distuils import sysconfig
print sysconfig.get_python_lib()

修改PYTHONPATH的方法:

Python的import语句只会找到位于PYTHONPATH中包含的目录的包。

你可以通过访问以下内容来检查和更改你的路径:

import sys
print sys.path
sys.path.append("/home/myname/lib")

除此之外,你可以像设置其他环境变量一样设置PYTHONPATH环境变量,或者你可以使用:

  • .pth文件:位于已经在PYTHONPATH中的目录中的*.pth文件会被读取,每一行都会被添加到你的PYTHONPATH中。基本上,每次你想把一个包复制到PYTHONPATH中的某个目录时,你可以创建一个mypackages.pth文件。关于*.pth文件的更多信息,请查看site模块
  • egg-link文件:Python eggs的内部结构,它们是符号链接的跨平台替代品。创建一个egg链接文件类似于创建一个pth文件。
  • site.py的修改

要将/home/myname/lib添加到site-packages,你可以创建一个*.pth文件。文件名无所谓,但最好选择一个合理的名字。

让我们创建一个myname.pth

# myname.pth
/home/myname/lib

就这样。把这个文件放到sysconfig.get_python_lib()所在的目录或你的PYTHONPATH中的任何其他目录中,/home/myname/lib就会被添加到路径中。

撰写回答