我如何知道Python模块是否存在,而不导入它?

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

try:
    import eggs
except ImportError:
    pass

当前回答

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。

如果你导入了你现有的模块,而你的模块中恰好有一个ImportError(例如,第1行有错字),结果将是你的模块不存在。

这将花费您大量的回溯来确定您的模块是否存在,ImportError被捕获并使事情无声地失败。

其他回答

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

from pkgutil import iter_modules

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

我写了这个helper函数:

def is_module_available(module_name):
    if sys.version_info < (3, 0):
        # python 2
        import importlib
        torch_loader = importlib.find_loader(module_name)
    elif sys.version_info <= (3, 3):
        # python 3.0 to 3.3
        import pkgutil
        torch_loader = pkgutil.find_loader(module_name)
    elif sys.version_info >= (3, 4):
        # python 3.4 and above
        import importlib
        torch_loader = importlib.util.find_spec(module_name)

    return torch_loader is not None

使用importlib.util.find_spec(module_name) (Python 3.4+)。

Python2: imp.find_module

要检查import是否能在python2中找到一些东西,使用imp:

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

要找到点导入,你需要做更多的事情:

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(与Python 3部分大致相同:

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

Python 3

Python 3≤3.3:importlib.find_loader

你应该使用importlib。我是这样做的:

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

我的期望是,如果你能找到一个加载器,那么它就存在了。你也可以更聪明一点,比如过滤掉你将接受的加载器。例如:

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)

Python 3≥3.4:importlib.util.find_spec

在Python 3.4中importlib。Python文档已弃用,取而代之的是importlib.util.find_spec。推荐使用importlib.util.find_spec方法。还有其他的,比如进口机械。FileFinder,如果你想要加载一个特定的文件,它很有用。弄清楚如何使用它们超出了本文的范围。

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

这也适用于相对导入,但你必须提供初始包,所以你还可以这样做:

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

虽然我确信这样做是有原因的,但我不确定是什么原因。

警告

当试图找到子模块时,它将导入父模块(对于上述所有方法)!

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.util.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 for importlib @lucas-guido for Python 3.3+弃用find_loader @enpenax for pkgutils。Python 2.7中的find_loader行为

Go_as的回答是一行:

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

你也可以使用importlib。util直接

import importlib.util    

def module_exists_without_import(module_name):    
    spec = importlib.util.find_spec(module_name)
    return spec is not None