如何检查模块/库/包是否是python标准库的一部分?

如何检查模块/库/包是否是python标准库的一部分?,python,module,package,native,Python,Module,Package,Native,我已经用pip安装了太多的库/模块/包,现在我无法区分哪些是python标准库的本机库,哪些不是。当我的代码在我的机器上工作,但在其他任何地方都不工作时,这会导致问题 如何检查我在代码中导入的模块/库/包是否来自python stdlib? 假设检查是在具有所有外部库/模块/包的机器上完成的,否则我可以在没有这些库/模块/包的另一台机器上尝试导入 例如,我确信这些导入可以在我的机器上工作,但当它在一台只有普通Python安装的机器上时,它会中断: from bs4 import Beautifu

我已经用pip安装了太多的库/模块/包,现在我无法区分哪些是python标准库的本机库,哪些不是。当我的代码在我的机器上工作,但在其他任何地方都不工作时,这会导致问题

如何检查我在代码中导入的模块/库/包是否来自python stdlib?

假设检查是在具有所有外部库/模块/包的机器上完成的,否则我可以在没有这些库/模块/包的另一台机器上尝试导入

例如,我确信这些导入可以在我的机器上工作,但当它在一台只有普通Python安装的机器上时,它会中断:

from bs4 import BeautifulSoup
import nltk
import PIL
import gensim

标准库是在python中定义的。您可以在那里搜索,或者将模块名称放入列表中,并通过编程方式进行检查

或者,在python3.4中有一个新的函数,允许忽略一定数量的用户定义的库路径。在python的早期版本中,可以使用
-s
忽略每个用户的环境,使用
-E
忽略系统定义的变量

在python2中,检查模块是否属于标准库的一个非常简单的方法是清除
sys.path

>>> import sys
>>> sys.path = []
>>> import numpy
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named numpy
>>> import traceback
>>> import os
>>> import re
我使用了
traceback
模块来获取库路径,因为这应该适用于任何系统


对于内置模块(stdlib模块的子集),您可以检查

您必须检查已导入的所有模块,以查看其中是否有任何模块位于标准库之外

以下脚本不是防弹的,但应该为您提供一个起点:

import sys
import os

external = set()
exempt = set()
paths = (os.path.abspath(p) for p in sys.path)
stdlib = {p for p in paths
          if p.startswith((sys.prefix, sys.real_prefix)) 
          and 'site-packages' not in p}
for name, module in sorted(sys.modules.items()):
    if not module or name in sys.builtin_module_names or not hasattr(module, '__file__'):
        # an import sentinel, built-in module or not a real module, really
        exempt.add(name)
        continue

    fname = module.__file__
    if fname.endswith(('__init__.py', '__init__.pyc', '__init__.pyo')):
        fname = os.path.dirname(fname)

    if os.path.dirname(fname) in stdlib:
        # stdlib path, skip
        exempt.add(name)
        continue

    parts = name.split('.')
    for i, part in enumerate(parts):
        partial = '.'.join(parts[:i] + [part])
        if partial in external or partial in exempt:
            # already listed or exempted
            break
        if partial in sys.modules and sys.modules[partial]:
            # just list the parent name and be done with it
            external.add(partial)
            break

for name in external:
    print name, sys.modules[name].__file__

这是一个新模块,在脚本中导入所有模块后再导入,它将打印它认为不属于标准库的所有模块。

@Bakuriu的回答对我非常有用。我遇到的唯一问题是,如果您想检查某个特定模块是否为stdlib,但该模块是否已经导入。在这种情况下,
sys.modules
将只有一个条目,因此即使剥离了
sys.path
,导入也将成功:

In [1]: import sys

In [2]: import virtualenv

In [3]: sys.path = []

In [4]: try:
    __import__('virtualenv')
except ImportError:
    print(False)
else:
    print(True)
   ...:
True
vs

我提出了以下解决方案,似乎在Python2和Python3中都有效:

from __future__ import unicode_literals, print_function
import sys
from contextlib import contextmanager
from importlib import import_module


@contextmanager
def ignore_site_packages_paths():
    paths = sys.path
    # remove all third-party paths
    # so that only stdlib imports will succeed
    sys.path = list(filter(
        None,
        filter(lambda i: 'site-packages' not in i, sys.path)
    ))
    yield
    sys.path = paths


def is_std_lib(module):
    if module in sys.builtin_module_names:
        return True

    with ignore_site_packages_paths():
        imported_module = sys.modules.pop(module, None)
        try:
            import_module(module)
        except ImportError:
            return False
        else:
            return True
        finally:
            if imported_module:
                sys.modules[module] = imported_module

您可以跟踪源代码

我想您可以从这里开始:使用virtualenv。它是专门为避免这些问题而构建的。它本身并不是一个答案,但如果您遵循它,将更容易看出哪些
import
s是第三方的“原生python”通常指“纯python”,例如,不使用任何C或其他非python语言扩展。相反,您谈论的是标准库与外部依赖关系。啊,@martijnpieters,感谢您关于“本机python”的注释但这不是关于stdlib和第三方,而是非纯第三方和纯Python第三方;我认为OP在这里是混合术语
bs4
是纯Python,而PIL肯定不是。两者都不会安装在新机器上。@triplee,这是关于stdlib和第三方的。因为我的合作者的机器上没有安装第三方LIB,所以他们非常恼火。。。给我留下一些问题,比如“你怎么能只做两行X?”。。。lolz
In [1]: import sys

In [2]: import virtualenv

In [3]: sys.path = []

In [4]: try:
    __import__('virtualenv')
except ImportError:
    print(False)
else:
    print(True)
   ...:
True
In [1]: import sys

In [2]: sys.path = []

In [3]: try:
    __import__('virtualenv')
except ImportError:
    print(False)
else:
    print(True)
   ...:
False
from __future__ import unicode_literals, print_function
import sys
from contextlib import contextmanager
from importlib import import_module


@contextmanager
def ignore_site_packages_paths():
    paths = sys.path
    # remove all third-party paths
    # so that only stdlib imports will succeed
    sys.path = list(filter(
        None,
        filter(lambda i: 'site-packages' not in i, sys.path)
    ))
    yield
    sys.path = paths


def is_std_lib(module):
    if module in sys.builtin_module_names:
        return True

    with ignore_site_packages_paths():
        imported_module = sys.modules.pop(module, None)
        try:
            import_module(module)
        except ImportError:
            return False
        else:
            return True
        finally:
            if imported_module:
                sys.modules[module] = imported_module