如何找到Python中任何包的“导入名称”?

34 投票
5 回答
13731 浏览
提问于 2025-04-17 00:18

我想知道有没有一种可靠且一致的方法来获取一个Python包的“导入名称”或命名空间。举个例子:

包名; django-haystack
导入名称; haystack

或者

包名; ipython
导入名称; IPython

到目前为止,我知道PyPi并没有存储这些信息,我用PyPiXmlRpc检查过。

我还尝试自动下载这个包,解压它,然后查看.egg-info文件夹,但有些包根本没有这个文件夹。

任何帮助都将不胜感激,并且会用于一个很不错的小工具 :)

5 个回答

5

原则上,你需要获取这些信息的所有内容都在每个包里应该有的 setup.py 文件中。这个信息大致包括了包的名称、py_modules、ext_package 和 ext_modules,这些都是 Distribution 对象的一部分。实际上,这里有一个小脚本,它模拟了 distutils.core.setup,专门用来获取这些信息。

import distutils.core
distutils.core._setup_stop_after = "config"
_real_setup = distutils.core.setup
def _fake_setup(*args, **kwargs):
    global dist
    dist = _real_setup(*args, **kwargs)

distutils.core.setup = _fake_setup

import sys
setup_file = sys.argv[1]
sys.argv[:] = sys.argv[1:]
import os.path
os.chdir(os.path.dirname(setup_file))

execfile(os.path.basename(setup_file))

cat = lambda *seq: sum((i for i in seq if i is not None), [])
pkgs = set(package.split('.')[0] for package
           in cat(dist.packages,
                  dist.py_modules,
                  [m.name for m in cat(dist.ext_modules)],
                  [m.name for m in cat(dist.ext_package)]))

print "\n".join(pkgs)

对于很多包来说,这个方法效果很好,但以 numpy 为例,它就不行。因为 numpy 自己提供了 distutils,而且我没有找到明显的解决办法。

10

轮子

我知道这个问题已经有点老了,但wheel包现在已经被发明出来了!因为wheel其实就是一个压缩文件,解压后会放到lib/site-packages目录里,所以查看这个wheel文件的内容可以让你知道最上层的导入。

>>> import zipfile
>>> zf = zipfile.ZipFile('setuptools-35.0.2-py2.py3-none-any.whl')
>>> top_level = set([x.split('/')[0] for x in zf.namelist()])
>>> # filter out the .dist-info directory
>>> top_level = [x for x in top_level if not x.endswith('.dist-info')]
>>> top_level 
['setuptools', 'pkg_resources', 'easy_install.py']

所以setuptools实际上给你提供了三个最上层的导入!

pip下载

现在pip有了一个下载命令,你只需运行 pip download setuptools(或者你喜欢的任何包),然后就可以查看它的内容。

反向查找

从Python 3.10开始,有一个方便的功能可以进行反向查找(给定导入名称,找出对应的包)。官方的文档在这里

from importlib.metadata import packages_distributions
packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'],  ...}

对于正向查找,你也可以简单地构建这个反向字典。

9

请注意,你这里所说的“包”其实不是包,而是一个叫做发行版的东西。一个发行版可以包含零个或多个模块或包。这意味着发行版和包之间并不是一一对应的关系。

我不太确定有没有办法在不安装发行版的情况下,知道它会安装哪些模块和包,除了实际安装它,然后查看文件系统的变化,看看新增了哪些包、模块和pth文件。

撰写回答