如何在不导入的情况下检查python模块是否存在
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14050281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to check if a python module exists without importing it
提问by yarbelk
I need to know if a python module exists, without importing it.
我需要知道 python 模块是否存在,而不需要导入它。
Importing something that might not exist (not what I want):
导入可能不存在的东西(不是我想要的):
try:
import eggs
except ImportError:
pass
采纳答案by yarbelk
Python2
蟒蛇2
To check if import can find something in python2, using imp
要检查导入是否可以在 python2 中找到一些东西,使用 imp
import imp
try:
imp.find_module('eggs')
found = True
except ImportError:
found = False
To find dotted imports, you need to do more:
要查找虚线导入,您需要执行更多操作:
import imp
try:
spam_info = imp.find_module('spam')
spam = imp.load_module('spam', *spam_info)
imp.find_module('eggs', spam.__path__) # __path__ is already a list
found = True
except ImportError:
found = False
You can also use pkgutil.find_loader(more or less the same as the python3 part
您也可以使用pkgutil.find_loader(或多或少与python3部分相同
import pkgutil
eggs_loader = pkgutil.find_loader('eggs')
found = eggs_loader is not None
Python3
蟒蛇3
Python3 ≤ 3.3
Python3 ≤ 3.3
You should use importlib, How I went about doing this was:
你应该使用importlib,我是如何做到这一点的:
import importlib
spam_loader = importlib.find_loader('spam')
found = spam_loader is not None
My expectation being, if you can find a loader for it, then it exists. You can also be a bit more smart about it, like filtering out what loaders you will accept. For example:
我的期望是,如果你能为它找到一个加载器,那么它就存在。你也可以更聪明一点,比如过滤掉你会接受的加载器。例如:
import importlib
spam_loader = importlib.find_loader('spam')
# only accept it as valid if there is a source file for the module - no bytecode only.
found = issubclass(type(spam_loader), importlib.machinery.SourceFileLoader)
Python3 ≥ 3.4
Python3≥3.4
In Python3.4 importlib.find_loaderpython docswas deprecated in favour of importlib.util.find_spec. The recommended method is the importlib.util.find_spec. There are others like importlib.machinery.FileFinder, which is useful if you're after a specific file to load. Figuring out how to use them is beyond the scope of this.
在 Python3.4 中,importlib.find_loaderpython 文档被弃用,取而代之的是importlib.util.find_spec. 推荐的方法是importlib.util.find_spec. 还有其他像importlib.machinery.FileFinder,如果您要加载特定文件,这很有用。弄清楚如何使用它们超出了本文的范围。
import importlib
spam_spec = importlib.util.find_spec("spam")
found = spam_spec is not None
This also works with relative imports but you must supply the starting package, so you could also do:
这也适用于相对导入,但您必须提供起始包,因此您也可以这样做:
import importlib
spam_spec = importlib.util.find_spec("..spam", package="eggs.bar")
found = spam_spec is not None
spam_spec.name == "eggs.spam"
While I'm sure there exists a reason for doing this - I'm not sure what it would be.
虽然我确定这样做是有原因的 - 我不确定它会是什么。
WARNING
警告
When trying to find a submodule, it will import the parent module (for allof the above methods)!
在尝试查找子模块时,它将导入父模块(对于上述所有方法)!
food/
|- __init__.py
|- eggs.py
## __init__.py
print("module food loaded")
## eggs.py
print("module eggs")
were you then to run
>>> import importlib
>>> spam_spec = importlib.find_spec("food.eggs")
module food loaded
ModuleSpec(name='food.eggs', loader=<_frozen_importlib.SourceFileLoader object at 0x10221df28>, origin='/home/user/food/eggs.py')
comments welcome on getting around this
欢迎评论解决这个问题
Acknowledgements
致谢
- @rvighne for importlib
- @lucas-guido for python3.3+ depricating
find_loader - @enpenax for pkgutils.find_loader behaviour in python2.7
- @rvighne 用于 importlib
- @lucas-guido for python3.3+ 贬低
find_loader - @enpenax 用于 python2.7 中的 pkgutils.find_loader 行为
回答by ArtOfWarfare
Use one of the functions from pkgutil, for example:
from pkgutil import iter_modules
def module_exists(module_name):
return module_name in (name for loader, name, ispkg in iter_modules())
回答by Zulu
After use yarbelk's response, I've made this for don't have to import ìmp.
使用 yarbelk 的回复后,我做了这个,因为不必导入ìmp.
try:
__import__('imp').find_module('eggs')
# Make things with supposed existing module
except ImportError:
pass
Useful in Django's settings.pyfor example.
settings.py例如在 Django 中很有用。
回答by go_as
I came across this question while searching for a way to check if a module is loaded from the command lineand would like to share my thoughts for the ones coming after me and looking for the same:
我在寻找一种检查模块是否从命令行加载的方法时遇到了这个问题, 我想分享我对那些在我之后寻找相同内容的人的想法:
Linux/UNIX script file method: make a file module_help.py:
Linux/UNIX 脚本文件方法:制作文件module_help.py:
#!/usr/bin/env python
help('modules')
Then make sure it's executable: chmod u+x module_help.py
然后确保它是可执行的: chmod u+x module_help.py
And call it with a pipeto grep:
并用pipeto调用它grep:
./module_help.py | grep module_name
Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the interpreter console. If the argument is a string, then the string is looked up as the name of a module, function, class, method, keyword, or documentation topic, and a help page is printed on the console. If the argument is any other kind of object, a help page on the object is generated.
调用内置的帮助系统。(此函数用于交互使用。)如果没有给出参数,交互帮助系统将在解释器控制台上启动。如果参数是string,则该 string 被查找为模块、函数、类、方法、关键字或文档主题的名称,并在控制台上打印帮助页面。如果参数是任何其他类型的对象,则会生成有关该对象的帮助页面。
Interactive method: in the console load python
交互方式:在控制台加载python
>>> help('module_name')
If found quit reading by typing q
To exit the python interactive session press Ctrl+ D
如果发现通过键入退出阅读q
要退出 python 交互式会话,请按Ctrl+D
Windows script file methodalso Linux/UNIX compatible, and better overall:
Windows 脚本文件方法也与 Linux/UNIX 兼容,并且总体上更好:
#!/usr/bin/env python
import sys
help(sys.argv[1])
Calling it from the command like:
从命令中调用它,例如:
python module_help.py site
Would output:
会输出:
Help on module site:
NAMEsite - Append module search paths for third-party packages to sys.path.
FILE/usr/lib/python2.7/site.py
MODULE DOCShttp://docs.python.org/library/site
DESCRIPTION
...
:
模块站点上的帮助:
NAMEsite - 将第三方包的模块搜索路径附加到 sys.path。
FILE/usr/lib/python2.7/site.py
MODULE DOCShttp://docs.python.org/library/site
DESCRIPTION
...
:
and you'd have to press qto exit interactive mode.
并且您必须按q退出交互模式。
Using it unknown module:
使用它未知的模块:
python module_help.py lkajshdflkahsodf
Would output:
会输出:
no Python documentation found for 'lkajshdflkahsodf'
没有找到“lkajshdflkahsodf”的 Python 文档
and exit.
并退出。
回答by go_as
go_as's answer as a one liner
go_as 作为一个班轮的回答
python -c "help('modules');" | grep module
回答by enpenax
Python 2, without relying ImportError
Python 2,不依赖ImportError
Until the current answer is updated, here is the way for Python 2
在更新当前答案之前,这是Python 2 的方法
import pkgutil
import importlib
if pkgutil.find_loader(mod) is not None:
return importlib.import_module(mod)
return None
Why another answer?
为什么是另一个答案?
A lot of answers make use of catching an ImportError. The problem with that is, that we cannot know what throws the ImportError.
很多答案都利用了捕获ImportError. 问题在于,我们无法知道是什么引发了ImportError.
If you import your existantmodule and there happens to be an ImportErrorin your module (e.g. typo on line 1), the result will be that your module does not exist. It will take you quite the amount of backtracking to figure out that your module exists and the ImportErroris caught and makes things fail silently.
如果您导入您的现有模块并且您的模块中碰巧有一个ImportError(例如第 1 行的拼写错误),结果将是您的模块不存在。您需要进行大量的回溯才能确定您的模块是否存在并被ImportError捕获并使事情无声无息地失败。
回答by Marcin Raczyński
There is no way to reliably check if "dotted module" is importable without importing its parent package. Saying this, there are many solutions to problem "how to check if Python module exists".
在不导入其父包的情况下,无法可靠地检查“虚线模块”是否可导入。话虽如此,“如何检查Python模块是否存在”的问题有很多解决方案。
Below solution address the problem that imported module can raise ImportError even it exists. We want to distinguish that situation from such in which module does not exist.
下面的解决方案解决了导入模块即使存在也可能引发 ImportError 的问题。我们想将这种情况与不存在模块的情况区分开来。
Python 2:
蟒蛇2:
import importlib
import pkgutil
import sys
def find_module(full_module_name):
"""
Returns module object if module `full_module_name` can be imported.
Returns None if module does not exist.
Exception is raised if (existing) module raises exception during its import.
"""
module = sys.modules.get(full_module_name)
if module is None:
module_path_tail = full_module_name.split('.')
module_path_head = []
loader = True
while module_path_tail and loader:
module_path_head.append(module_path_tail.pop(0))
module_name = ".".join(module_path_head)
loader = bool(pkgutil.find_loader(module_name))
if not loader:
# Double check if module realy does not exist
# (case: full_module_name == 'paste.deploy')
try:
importlib.import_module(module_name)
except ImportError:
pass
else:
loader = True
if loader:
module = importlib.import_module(full_module_name)
return module
Python 3:
蟒蛇3:
import importlib
def find_module(full_module_name):
"""
Returns module object if module `full_module_name` can be imported.
Returns None if module does not exist.
Exception is raised if (existing) module raises exception during its import.
"""
try:
return importlib.import_module(full_module_name)
except ImportError as exc:
if not (full_module_name + '.').startswith(exc.name + '.'):
raise
回答by dibrovsd
in django.utils.module_loading.module_has_submodule
在 django.utils.module_loading.module_has_submodule
import sys
import os
import imp
def module_has_submodule(package, module_name):
"""
check module in package
django.utils.module_loading.module_has_submodule
"""
name = ".".join([package.__name__, module_name])
try:
# None indicates a cached miss; see mark_miss() in Python/import.c.
return sys.modules[name] is not None
except KeyError:
pass
try:
package_path = package.__path__ # No __path__, then not a package.
except AttributeError:
# Since the remainder of this function assumes that we're dealing with
# a package (module with a __path__), so if it's not, then bail here.
return False
for finder in sys.meta_path:
if finder.find_module(name, package_path):
return True
for entry in package_path:
try:
# Try the cached finder.
finder = sys.path_importer_cache[entry]
if finder is None:
# Implicit import machinery should be used.
try:
file_, _, _ = imp.find_module(module_name, [entry])
if file_:
file_.close()
return True
except ImportError:
continue
# Else see if the finder knows of a loader.
elif finder.find_module(name):
return True
else:
continue
except KeyError:
# No cached finder, so try and make one.
for hook in sys.path_hooks:
try:
finder = hook(entry)
# XXX Could cache in sys.path_importer_cache
if finder.find_module(name):
return True
else:
# Once a finder is found, stop the search.
break
except ImportError:
# Continue the search for a finder.
continue
else:
# No finder found.
# Try the implicit import machinery if searching a directory.
if os.path.isdir(entry):
try:
file_, _, _ = imp.find_module(module_name, [entry])
if file_:
file_.close()
return True
except ImportError:
pass
# XXX Could insert None or NullImporter
else:
# Exhausted the search, so the module cannot be found.
return False
回答by User9123
You could just write a little script that would try to import all the modules and tell you which ones are failing and which ones are working:
您可以编写一个小脚本,尝试导入所有模块并告诉您哪些模块失败,哪些模块正常工作:
import pip
if __name__ == '__main__':
for package in pip.get_installed_distributions():
pack_string = str(package).split(" ")[0]
try:
if __import__(pack_string.lower()):
print(pack_string + " loaded successfully")
except Exception as e:
print(pack_string + " failed with error code: {}".format(e))
Output:
输出:
zope.interface loaded successfully
zope.deprecation loaded successfully
yarg loaded successfully
xlrd loaded successfully
WMI loaded successfully
Werkzeug loaded successfully
WebOb loaded successfully
virtualenv loaded successfully
...
Word of warning this will try to import everythingso you'll see things like PyYAML failed with error code: No module named pyyamlbecause the actual import name is just yaml. So as long as you know your imports this should do the trick for you.
警告的话,这将尝试导入所有内容,因此您会看到类似的内容,PyYAML failed with error code: No module named pyyaml因为实际导入名称只是 yaml。所以只要你知道你的进口,这应该对你有用。
回答by Hymanotonye
You can also use importlibdirectly
也可以importlib直接使用
import importlib
try:
importlib.import_module(module_name)
except ImportError:
# Handle error

