224

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

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

try:
    import eggs
except ImportError:
    pass
4

14 回答 14

254

Python2

要检查导入是否可以在 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(或多或少与 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 文档被弃用,取而代之的是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 用于 importlib
  • @lucas-guido 用于 python3.3+ 贬低find_loader
  • @enpenax 用于 python2.7 中的 pkgutils.find_loader 行为
于 2012-12-27T06:17:22.190 回答
35

Python 3 >= 3.6:ModuleNotFoundError

ModuleNotFoundErrorpython 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

于 2017-12-28T11:46:48.290 回答
13

在使用 yarbelk 的回复后,我做了这个,因为不需要 import ìmp

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

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

于 2014-07-30T19:23:36.547 回答
12

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

于 2015-11-10T06:48:28.583 回答
8

go_as 作为一个班轮的回答

 python -c "help('modules');" | grep module
于 2015-04-14T03:17:10.063 回答
7

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

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

#!/usr/bin/env python

help('modules')

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

并用pipeto调用它grep

./module_help.py | grep module_name

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

交互方式:在控制台加载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 文档

并退出。

于 2015-04-10T09:46:24.807 回答
6

我写了这个辅助函数:

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
于 2019-10-17T16:59:03.097 回答
5

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

from pkgutil import iter_modules

def module_exists(module_name):
    return module_name in (name for loader, name, ispkg in iter_modules())
于 2014-07-03T12:00:58.063 回答
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。所以只要你知道你的进口,这应该为你解决问题。

于 2017-02-02T14:17:47.857 回答
3

AskUbuntu 的一个更简单的 if 语句:如何检查模块是否安装在 Python 中?

import sys
print('eggs' in sys.modules)
于 2018-12-03T03:42:50.987 回答
1

如果不导入其父包,就无法可靠地检查“dotted module”是否可导入。说到这里,对于“如何检查 Python 模块是否存在”这个问题有很多解决方案。

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

蟒蛇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

蟒蛇 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
于 2016-01-27T12:17:04.463 回答
1

在 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
于 2016-03-20T15:03:56.267 回答
1

如果您知道文件的位置并想检查相应的 python 代码文件是否具有该模块,您可以简单地通过astorpython 中的包进行检查,这里是一个快速示例:

"""
check if module Function exists or not without importing a python package file
"""
import ast 
import astor 
 
tree = astor.parse_file('handler.py')    
method_to_check = 'handle'
for item in tree.body: 
    if isinstance(item, ast.FunctionDef): 
        if item.name == method_to_check: 
            print('method exists') 
            break 
于 2021-08-19T19:09:10.090 回答
0

也可以importlib直接使用

import importlib

try:
    importlib.import_module(module_name)
except ImportError:
    # Handle error
于 2017-08-17T20:39:27.313 回答