20

我正在对各种模块进行一些解析和自省,但我不想解析内置模块。现在,内置模块没有像 a 这样的特殊类型types.BuiltinFunctionType,那么我该怎么做呢?

>>> import CornedBeef
>>> CornedBeef
<module 'CornedBeef' from '/meatish/CornedBeef.pyc'>
>>> CornedBeef.__file__
'/meatish/CornedBeef.pyc'
>>> del CornedBeef.__file__
>>> CornedBeef
<module 'CornedBeef' (built-in)>

根据 Python,如果一个模块没有__file__属性,它显然是内置的。这是否意味着这hasattr(SomeModule, '__file__')是检查模块是否内置的方法?当然,它并不完全常见del SomeModule.__file__,但是有没有更可靠的方法来确定模块是否是内置的?

4

4 回答 4

11

sys.builtin_module_names

一个字符串元组,给出编译到这个 Python 解释器中的所有模块的名称。(此信息不能以任何其他方式获得 - modules.keys() 仅列出导入的模块。)

于 2011-02-07T21:59:53.830 回答
9

如果您只是按要求考虑builtins,那么接受的答案显然是正确的。

就我而言,我也在寻找标准库,我的意思是一个给定 Python 发行版附带的所有可导入模块的列表。已多次提出有关此问题的问题,但我找不到包含我正在寻找的所有内容的答案。

我的用例是x在 Pythonimport x语句中任意存储一个:

  • 包含在 Python 标准库 + 内置程序中
  • 作为第三方模块安装
  • 两者都不

这将适用于 virtualenvs 或全局安装。它查询运行脚本的任何 python 二进制文件的分布。最后一块确实超出了virtualenv,但我认为这是所需的行为。

# You may need to use setuptools.distutils depending on Python distribution (from setuptools import distutils)
import distutils
import glob
import os
import pkgutil
import sys    

def get_python_library():

    # Get list of the loaded source modules on sys.path.
    modules = { 
        module
        for _, module, package in list(pkgutil.iter_modules())
        if package is False
    }

    # Glob all the 'top_level.txt' files installed under site-packages.
    site_packages = glob.iglob(os.path.join(os.path.dirname(os.__file__) 
                    + '/site-packages', '*-info', 'top_level.txt'))

    # Read the files for the import names and remove them from the modules list.
    modules -= {open(txt).read().strip() for txt in site_packages}

    # Get the system packages.
    system_modules = set(sys.builtin_module_names)

    # Get the just the top-level packages from the python install.
    python_root = distutils.sysconfig.get_python_lib(standard_lib=True)
    _, top_level_libs, _ = list(os.walk(python_root))[0]

    return sorted(top_level_libs + list(modules | system_modules))

退货

排序的导入列表:[..., 'imaplib', 'imghdr', 'imp', 'importlib', 'imputil', 'inspect', 'io', ...]

说明

我把它分成几块,这样每个组需要的原因就很清楚了。

  • modules

    • pkgutil.iter_modules调用扫描所有加载的模块sys.path并返回一个(module_loader, name, ispkg)元组生成器。
    • 我把它变成一个集合并过滤掉包,因为这里我们只关心源模块。
  • site_packages

    • 获取常规站点包目录下所有已安装包的列表,并将它们从modules列表中删除。这大致对应于第三方部门。
    • 这是最难做对的部分。许多事情几乎都奏效了,例如pip.get_installed_distributionsor site。但pip返回 PyPi 上的模块名称,而不是导入源文件时的模块名称。某些病态包裹会从裂缝中溜走,例如:
      • requests-futures导入为requests_futures.
      • colors,这实际上是ansicolors在 PyPi 上,因此混淆了任何合理的启发式。
    • 我确信有一些低使用率的模块不包含top_level.txt在他们的包中。但这涵盖了我 100% 的用例,似乎适用于正确配置的所有内容。
  • system_modules

    • 如果您没有明确要求它们,您将不会获得这些系统模块,例如sys,gcerrno其他一些可选模块
  • top_level_libs

    • distutils.sysconfig.get_python_lib(standard_lib=True)调用返回平台无关标准库的顶级目录。
    • 这些很容易被忽略,因为它们可能与其他模块不在同一 python 路径下。如果你在 OSX 上运行 virtualenv,这些模块实际上是从系统安装中导入的。这些模块包括emailloggingxml更多。

结论

对于我的 2013 MacBookPro,我找到了 403 个模块进行python2.7安装。

   >>> print(sys.version)
   2.7.10 (default, Jul 13 2015, 12:05:58)
   [GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)]
   >>> print(sys.hexversion)
   34015984
   >>> python_stdlib = get_python_libirary()
   >>> len(python_stdlib)
   403

我提出了代码和输出的要点。如果您认为我错过了课程或包含了虚假模块,我想听听。

* 备择方案

  • 在写这篇文章时,我挖掘了pipsetuptoolsAPI。此信息可能通过单个模块获得,但您确实需要了解该 API 的使用方式。

  • 在我开始这个之前,我被告知six有一个专门针对这个问题的功能。可能存在是有道理的,但我自己找不到。

于 2016-05-15T20:36:13.970 回答
4

您可以使用imp.is_builtin来查看模块名称是否与内置模块匹配,但我想不出任何方法可以可靠地实际自省模块对象。

您还可以尝试以下方法:

>>> import imp
>>> f, path, desc = imp.find_module("sys")
>>> desc
('', '', 6)
>>> desc[2] == imp.C_BUILTIN
True
于 2011-02-07T15:03:08.187 回答
2

当您说“内置”时,您是指用 C 语言编写的,还是标准库的一部分?如果您的意思是第一个,那么寻找__file__是正确的做法。如您所见,即使是 Python 解释器也使用存在__file__作为内置指标。

如果您的意思是“标准库的一部分”,那么很难确定。

于 2011-02-07T14:48:17.120 回答