我已经用pip安装了很多库/模块/包,现在我无法区分python标准库本身哪个,哪些不是。当我的代码在我的机器上运行时,这会导致问题,但在其他任何地方都不起作用。
如何检查我在代码中导入的模块/库/包是否来自python stdlib?
假设检查是在具有所有外部库/模块/包的机器上完成的,否则我可以在没有它们的其他机器上执行try-except导入。
例如,我确信这些导入可以在我的机器上运行,但是当它只在一台只有普通Python安装的机器上运行时,会中断:
from bs4 import BeautifulSoup
import nltk
import PIL
import gensim
答案 0 :(得分:8)
您必须检查已导入的所有模块,以查看其中是否有任何模块位于标准库之外。
以下脚本不防弹,但应该为您提供一个起点:
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__
把它作为一个新模块,在脚本中的所有导入之后将其导入,它将打印它认为不是标准库的一部分的所有模块
答案 1 :(得分: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
模块来获取库路径,因为这应该适用于任何系统。
对于内置模块,它们是stdlib模块的子集,您可以检查sys.builtin_module_names
答案 2 :(得分: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
VS
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