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

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

try:
    import eggs
except ImportError:
    pass

当前回答

在使用yarbelk的响应后,我做了这个,所以我不需要导入ìmp。

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

例如,它在Django的settings.py文件中就很有用。

其他回答

我写了这个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

Ask Ubuntu的一个更简单的if语句,如何检查Python中是否安装了一个模块?:

import sys
print('eggs' in sys.modules)

在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

使用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行为

Python 3 >= 3.6: ModuleNotFoundError

ModuleNotFoundError已在Python 3.6中引入,可用于以下目的:

try:
    import eggs
except ModuleNotFoundError:
    # Error handling
    pass

当无法找到模块或其父模块之一时,将引发此错误。所以

try:
    import eggs.sub
except ModuleNotFoundError as err:
    # Error handling
    print(err)

如果找不到eggs模块,将打印类似于No module named 'eggs'的消息;但它会打印类似于没有名为“eggs”的模块。如果子模块找不到,但鸡蛋包可以找到,则Sub '。

有关ModuleNotFoundError的更多信息,请参阅导入系统的文档。