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

时间:2012-12-27 06:17:22

标签: python python-import

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

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

try:
    import eggs
except ImportError:
    pass

13 个答案:

答案 0 :(得分:167)

Python2

使用imp

检查导入是否可以在python2中找到某些内容
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(或多或少与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

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

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 docs中,我们弃用了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

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

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.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 python3.3 + depricating find_loader
  • @enpenax for python2.7中的pkgutils.find_loader行为

答案 1 :(得分:13)

在使用yarbelk的回复之后,我做了这个,因为不必导入ìmp

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

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

答案 2 :(得分:10)

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被捕获并使事情无声地失败。

答案 3 :(得分:8)

go_as的回答作为一个班轮

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

答案 4 :(得分:6)

我在寻找一种方法来检查模块是否从命令行加载时遇到了这个问题,并希望分享我对那些追随我的想法并寻找相同的想法:

Linux / UNIX脚本文件方法:制作文件module_help.py

#!/usr/bin/env python

help('modules')

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

并使用pipe拨打grep

./module_help.py | grep module_name
  

调用内置help system。 (此功能用于交互式使用。)如果未给出参数,则交互式帮助系统将在解释器控制台上启动。如果参数是字符串,则会将字符串作为模块的名称,函数,类,方法,关键字或文档主题以及帮助页面进行查找打印在控制台上。如果参数是任何其他类型的对象,则会生成对象的帮助页面。

交互式方法:在控制台中加载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      site - 将第三方软件包的模块搜索路径附加到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文档

然后退出。

答案 5 :(得分:5)

使用其中一个functions from pkgutil,例如:

from pkgutil import iter_modules

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

答案 6 :(得分:4)

您可以编写一个小脚本,尝试导入所有模块并告诉您哪些模块失败以及哪些模块正在运行:

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之类的内容,因为实际的导入名称只是yaml。所以只要你知道你的进口,这应该可以解决你的问题。

答案 7 :(得分:4)

Python 3&gt; = 3.6:ModuleNotFoundError

http://rextester.com/ESYBOO56762已在 python 3.6 中引入,可用于此目的

try:
    import eggs
except ModuleNotFoundError:
    # Error handling
    pass

如果找不到模块或其中一个模块,则会引发错误。所以

try:
    import eggs.sub
except ModuleNotFoundError as err:
    # Error handling
    print(err)
如果找不到No module named 'eggs'模块,

会打印一条类似eggs的邮件;但如果找不到No module named 'eggs.sub'模块但可以找到sub包,则会打印eggs之类的内容。

有关ModuleNotFoundError

的更多信息,请参阅ModuleNotFoundError

答案 8 :(得分:2)

您也可以直接使用importlib

import importlib

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

答案 9 :(得分:2)

AskUbuntu提供的更简单的if语句:How do I check whether a module is installed in Python?

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

答案 10 :(得分:0)

无法可靠地检查&#34;点线模块&#34;是可导入的,无需导入其父包。说到这里,有很多问题的解决方案&#34;如何检查Python模块是否存在&#34;。

下面的解决方案解决了导入模块即使存在也会引发ImportError的问题。我们希望将这种情况与不存在哪个模块的情况区分开来。

Python 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

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

答案 11 :(得分:0)

在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

答案 12 :(得分:0)

我写了这个辅助函数:

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