如何在不导入 Python 模块的情况下检查它是否存在

2025-02-14 09:49:00
admin
原创
49
摘要:问题描述:如何在不导入 Python 模块的情况下知道它是否存在?导入可能不存在的东西(不是我想要的)会导致:try: import eggs except ImportError: pass 解决方案 1:TL;DR)使用importlib.util.find_spec(module_nam...

问题描述:

如何在不导入 Python 模块的情况下知道它是否存在?

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

try:
    import eggs
except ImportError:
    pass

解决方案 1:

TL;DR)使用importlib.util.find_spec(module_name)(Python 3.4+)

Python2的:imp.find_module

要检查import是否能在 Python 2 中找到某些内容,请使用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.find_loader Python 文档已弃用,取而代之的是importlib.util.find_spec。推荐的方法是importlib.util.find_spec。还有其他方法importlib.machinery.FileFinder,例如 ,如果您要加载特定文件,则很有用。弄清楚如何使用它们超出了本文的范围。

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

这也适用于相对导入,但您必须提供起始包,因此您也可以执行以下操作:

import importlib.util
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 为 importlib

  • @lucas-guido 对于 Python 3.3+ 已弃用find_loader

  • @enpenax 表示 Python 2.7 中的 pkgutils.find_loader 行为

解决方案 2:

Python 3 >= 3.6:ModuleNotFoundError

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

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

解决方案 3:

在使用yarbelk 的回应之后,我已经这样做了,所以我不需要导入ìmp

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

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

解决方案 4:

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被捕获,从而使事情悄悄失败。

解决方案 5:

go_as 的答案是一行:

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

解决方案 6:

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

from pkgutil import iter_modules

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

解决方案 7:

我写了这个辅助函数:

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

解决方案 8:

以下是从命令行检查模块是否加载的方法:

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 文档

然后退出。

解决方案 9:

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

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。因此,只要您知道自己的导入内容,这就可以解决问题。

解决方案 10:

没有任何方法可以可靠地检查“带点模块”是否可以导入,而无需导入其父包。话虽如此,对于“如何检查 Python 模块是否存在”的问题,有很多解决方案。

以下解决方案解决了导入的模块即使存在也会引发 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:

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:

如果你知道文件的位置,并想检查相应的 Python 代码文件是否包含该模块,你可以通过Python 中的astor包进行检查。以下是一个简单的示例:

"""
Check if a 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

解决方案 13:

您也可以importlib.util直接使用

import importlib.util    

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

解决方案 14:

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

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

解决方案 15:

那怎么样:

 def module_is_available(the_path,module_folder_name):    
    return module_folder_name in os.listdir(the_path)

然后如果您想检查 sys.path 中当前的所有路径:

def module_is_available_in_sys_path(module_folder_name):        
    for p in sys.path:
        if module_is_available(p,module_folder_name)
            return True
    return False
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1590  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1361  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   18  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   18  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   19  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用