如何检查一个python模块是否存在,而不导入它

我需要知道是否存在python模块,而不导入它。

导入可能不存在的东西(不是我想要的):

try: import eggs except ImportError: pass 

Python2

要检查导入是否可以在python2中find某些东西,请使用imp

 import imp try: imp.find_module('eggs') found = True except ImportError: found = False 

要find加点的import,您需要做更多:

 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 

您也可以使用pkgutil.find_loader (或多或less与python3部分相同

 import pkgutil eggs_loader = pkgutil.find_loader('eggs') found = eggs_loader is not None 

Python3

Python3 <= 3.3

你应该使用importlib ,我怎么去做这个是:

 import importlib spam_loader = importlib.find_loader('spam') found = spam_loader is not None 

我的期望是,如果你可以find一个装载机,那么它存在。 你也可以更聪明点,比如过滤掉你会接受的装载者。 例如

 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.4中, importlib.find_loader python文档已被弃用,以支持importlib.util.find_spec 。 真的,你需要select任何具体的实现,build议是importlib.util.find_spec之一。 还有其他的像importlib.machinery.FileFinder ,如果你是在一个特定的文件加载后,这是有用的。 弄清楚如何使用它们超出了这个范围。

 import importlib spam_spec = importlib.util.find_spec("spam") found = spam_spec is not None 

这也适用于相对的import,但你必须提供起始包,所以你也可以:

 import importlib spam_spec = importlib.util.find_spec("..spam", package="eggs.bar") found = spam_spec is not None spam_spec.name == "eggs.spam" 

虽然我确信有这样做的理由 – 我不确定会是什么。

警告

当试图find一个子模块时,它会导入父模块(对于所有上述方法)!

 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') 

评论欢迎来解决这个问题

致谢

  • @rvighne为importlib
  • @ lucas-guido for python3.3 + find_loader
  • python2.7中的pkgutils.find_loader行为@enpenax

使用yarbelk的回应后,我已经做了这个不必导入ìmp

 try: __import__('imp').find_module('eggs') # Make things with supposed existing module except ImportError: pass 

例如,在Django的settings.py有用。

go_as作为一个class轮的答案

  python -c "help('modules');" | grep module 

使用pkgutil中的一个函数 ,例如:

 from pkgutil import iter_modules def module_exists(module_name): return module_name in (name for loader, name, ispkg in iter_modules()) 

我遇到这个问题的同时寻找一种方法来检查一个模块是否从命令行加载,并希望分享我的想法,为我后来寻找同样的:

Linux / UNIX脚本文件方法 :build立一个文件module_help.py

 #!/usr/bin/env python help('modules') 

然后确保它是可执行的: chmod u+x module_help.py

并用pipe调用grep

 ./module_help.py | grep module_name 

调用内置的帮助系统 。 (此function用于交互式使用 。)如果未提供参数,交互式帮助系统将在解释器控制台上启动。 如果参数是一个string ,那么该string被查找为模块 ,函数,类,方法,关键字或文档主题的名称,并在控制台上打印帮助页面。 如果参数是其他types的对象,则会生成对象上的帮助页面。

交互方法 :在控制台加载python

 >>> help('module_name') 

如果发现通过键入q退出阅读
要退出python交互式会话,请按Ctrl + D

Windows脚本文件的方法也与Linux / UNIX兼容, 总体来说更好

 #!/usr/bin/env python import sys help(sys.argv[1]) 

从以下命令调用它:

 python module_help.py site 

输出:

帮助模块站点:

NAME站点 – 将第三方软件包的模块searchpath追加到sys.path。

FILE /usr/lib/python2.7/site.py

MODULE DOCS http://docs.python.org/library/site

DESCRIPTION

你必须按q才能退出交互模式。

使用它未知的模块:

 python module_help.py lkajshdflkahsodf 

输出:

找不到'lkajshdflkahsodf'的Python文档

并退出。

Python 2,而不依赖于ImportError

直到当前的答案更新,这里是Python 2的方式

 import pkgutil import importlib if pkgutil.find_loader(mod) is not None: return importlib.import_module(mod) return None 

为什么还有其他答案

很多答案都使用捕获ImportError 。 那个问题是,我们不知道什么会引发ImportError

如果你导入你的existant模块,并且在你的模块中碰巧有一个ImportError (例如第1行上的错字),结果将会是你的模块不存在。 需要相当数量的回溯来确定你的模块是否存在, ImportError被捕获,并使得事情失败。

你可以写一个小脚本来试图导入所有的模块,并告诉你哪些是失败的,哪些正在工作:

 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)) 

输出:

 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 ... 

警告这个词会试图导入一切,所以你会看到像PyYAML failed with error code: No module named pyyaml东西PyYAML failed with error code: No module named pyyaml因为实际的导入名称只是yaml。 所以只要你知道你的import,这应该为你做的伎俩。

你也可以直接使用importlib

 import importlib try: importlib.import_module(module_name) except ImportError: # Handle error 

Python 2

没有办法可靠地检查“虚线模块”是否可导入而不导入其父包。 说到这个,“如何检查Python模块是否存在”问题有很多解决scheme。

以下解决scheme解决导入模块即使存在也会引起ImportError的问题。 我们想把这种情况与哪个模块不存在的情况区分开来。

 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 

在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