如何检查模块/库/包是不是是 python 标准库的一部分?
Posted
技术标签:
【中文标题】如何检查模块/库/包是不是是 python 标准库的一部分?【英文标题】:How to check if a module/library/package is part of the python standard library?如何检查模块/库/包是否是 python 标准库的一部分? 【发布时间】:2014-04-07 08:54:16 【问题描述】:我已经用 pip 安装了很多库/模块/包,现在我无法区分哪些是 Python 标准库的原生库,哪些不是。当我的代码在我的机器上运行但在其他任何地方都不起作用时,这会导致问题。
如何检查我在代码中导入的模块/库/包是否来自 python stdlib?
假设检查是在具有所有外部库/模块/包的机器上完成的,否则我可以简单地在没有它们的另一台机器上执行 try-except 导入。
例如,我确信这些导入可以在我的机器上运行,但是当它在仅安装了普通 Python 的机器上时,它会中断:
from bs4 import BeautifulSoup
import nltk
import PIL
import gensim
【问题讨论】:
我猜你可以从这里开始:docs.python.org/2/library/index.html 使用 virtualenv。它是专门为避免这些问题而构建的。 这不是一个答案,但如果您关注PEP-0008,则更容易看出哪些import
s 是第三方
'native python' 通常指的是'pure python',例如不使用任何 C 或其他非 Python 语言扩展。相反,您是在谈论标准库与外部依赖项。
啊,@martijnpieters,感谢关于“本机 python”的说明。 =)
【参考方案1】:
@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
对
In [1]: import sys
In [2]: sys.path = []
In [3]: try:
__import__('virtualenv')
except ImportError:
print(False)
else:
print(True)
...:
False
我提出了以下似乎适用于 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
可以关注源代码here
【讨论】:
【参考方案2】:您必须检查所有已导入的模块,以查看其中是否有任何模块位于标准库之外。
以下脚本不是防弹的,但应该为您提供一个起点:
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__
这是一个新模块,在脚本中的所有导入之后导入它,它会打印它认为不是标准库一部分的所有模块.
【讨论】:
【参考方案3】:标准库在python的documentation中定义。您可以在那里搜索,或将模块名称放入列表中并以编程方式检查。
另外,在 python3.4 中有一个新的isolated mode 允许忽略一定数量的用户定义的库路径。在以前的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
但是这在 python3.3+ 中不起作用:
>>> import sys
>>> sys.path = []
>>> import traceback
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'traceback'
[...]
这是因为从 python3.3 开始,导入机制发生了变化,导入标准库使用与导入任何其他模块相同的机制(请参阅documentation)。
在 python3.3 中,确保只有 stdlib 的导入成功的唯一方法是仅将标准库路径添加到 sys.path
,例如:
>>> import os, sys, traceback
>>> lib_path = os.path.dirname(traceback.__file__)
>>> sys.path = [lib_path]
>>> import traceback
>>> import re
>>> import numpy
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'numpy'
我使用traceback
模块来获取库路径,因为这应该适用于任何系统。
对于作为标准库模块的子集的内置模块,您可以查看sys.builtin_module_names
【讨论】:
但这不是关于 stdlib 与第三方的对比,而是非纯第三方与纯 Python 第三方的对比。 @tripleee:我不同意;我认为OP在这里混合了术语。bs4
是纯 Python,而 PIL 肯定不是。两者都不会安装在新机器上。
@triplee,这是关于 stdlib 与第三方的。因为第三方库没有安装在我的合作者的机器上,所以他们把他们惹恼了……给我留下了诸如“你怎么能在两行中做 X?”之类的问题。 ...大声笑以上是关于如何检查模块/库/包是不是是 python 标准库的一部分?的主要内容,如果未能解决你的问题,请参考以下文章