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

问题:如何在不导入的情况下检查python模块是否存在

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

导入可能不存在的内容(不是我想要的):

try:
    import eggs
except ImportError:
    pass

I need to know if a python module exists, without importing it.

Importing something that might not exist (not what I want):

try:
    import eggs
except ImportError:
    pass

回答 0

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

Python2

To check if import can find something in python2, using imp

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

To find dotted imports, you need to do more:

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

You can also use pkgutil.find_loader (more or less the same as the python3 part

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

Python3

Python3 ≤ 3.3

You should use importlib, How I went about doing this was:

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

My expectation being, if you can find a loader for it, then it exists. You can also be a bit more smart about it, like filtering out what loaders you will accept. For example:

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

In Python3.4 importlib.find_loader python docs was deprecated in favour of importlib.util.find_spec. The recommended method is the importlib.util.find_spec. There are others like importlib.machinery.FileFinder, which is useful if you’re after a specific file to load. Figuring out how to use them is beyond the scope of this.

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

This also works with relative imports but you must supply the starting package, so you could also do:

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

While I’m sure there exists a reason for doing this – I’m not sure what it would be.

WARNING

When trying to find a submodule, it will import the parent module (for all of the above methods)!

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')

comments welcome on getting around this

Acknowledgements

  • @rvighne for importlib
  • @lucas-guido for python3.3+ depricating find_loader
  • @enpenax for pkgutils.find_loader behaviour in python2.7

回答 1

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)

会显示一条消息,看起来像找不到No module named 'eggs'eggs模块;但将打印出类似这样No module named 'eggs.sub'如果只有sub模块无法找到,但eggs包可能被发现。

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

Python 3 >= 3.6: ModuleNotFoundError

The ModuleNotFoundError has been introduced in python 3.6 and can be used for this purpose

try:
    import eggs
except ModuleNotFoundError:
    # Error handling
    pass

The error is raised when a module or one of its parents cannot be found. So

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

would print a message that looks like No module named 'eggs' if the eggs module cannot be found; but would print something like No module named 'eggs.sub' if only the sub module couldn’t be found but the eggs package could be found.

See the documentation of the import system for more info on the ModuleNotFoundError


回答 2

在使用yarbelk的响应后,我做了这个,因为不必import ìmp

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

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

After use yarbelk’s response, I’ve made this for don’t have to import ìmp.

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

Useful in Django’s settings.pyfor example.


回答 3

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被捕获并使一切静默失败。

Python 2, without relying ImportError

Until the current answer is updated, here is the way for Python 2

import pkgutil
import importlib

if pkgutil.find_loader(mod) is not None:
    return importlib.import_module(mod)
return None

Why another answer?

A lot of answers make use of catching an ImportError. The problem with that is, that we cannot know what throws the ImportError.

If you import your existant module and there happens to be an ImportError in your module (e.g. typo on line 1), the result will be that your module does not exist. It will take you quite the amount of backtracking to figure out that your module exists and the ImportError is caught and makes things fail silently.


回答 4

go_as的答案

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

go_as’s answer as a one liner

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

回答 5

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

Linux / UNIX脚本文件方法:创建文件module_help.py

#!/usr/bin/env python

help('modules')

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

并用一个 pipetogrep

./module_help.py | grep module_name

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

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

然后退出。

I came across this question while searching for a way to check if a module is loaded from the command line and would like to share my thoughts for the ones coming after me and looking for the same:

Linux/UNIX script file method: make a file module_help.py:

#!/usr/bin/env python

help('modules')

Then make sure it’s executable: chmod u+x module_help.py

And call it with a pipe to grep:

./module_help.py | grep module_name

Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the interpreter console. If the argument is a string, then the string is looked up as the name of a module, function, class, method, keyword, or documentation topic, and a help page is printed on the console. If the argument is any other kind of object, a help page on the object is generated.

Interactive method: in the console load python

>>> help('module_name')

If found quit reading by typing q
To exit the python interactive session press Ctrl + D

Windows script file method also Linux/UNIX compatible, and better overall:

#!/usr/bin/env python

import sys

help(sys.argv[1])

Calling it from the command like:

python module_help.py site  

Would output:

Help on module site:

NAME site – Append module search paths for third-party packages to sys.path.

FILE /usr/lib/python2.7/site.py

MODULE DOCS http://docs.python.org/library/site

DESCRIPTION

:

and you’d have to press q to exit interactive mode.

Using it unknown module:

python module_help.py lkajshdflkahsodf

Would output:

no Python documentation found for ‘lkajshdflkahsodf’

and exit.


回答 6

使用pkgutil中的功能之一,例如:

from pkgutil import iter_modules

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

Use one of the functions from pkgutil, for example:

from pkgutil import iter_modules

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

回答 7

来自AskUbuntu的更简单的if语句:如何检查Python中是否安装了模块?

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

A simpler if statement from AskUbuntu: How do I check whether a module is installed in Python?

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

回答 8

您可以编写一个脚本来尝试导入所有模块,并告诉您哪些模块发生故障以及哪些模块正在工作:

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。因此,只要您知道自己的进口货,就可以为您解决问题。

You could just write a little script that would try to import all the modules and tell you which ones are failing and which ones are working:

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))

Output:

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
...

Word of warning this will try to import everything so you’ll see things like PyYAML failed with error code: No module named pyyaml because the actual import name is just yaml. So as long as you know your imports this should do the trick for you.


回答 9

我写了这个辅助函数:

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

I wrote this helper function:

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

回答 10

您也可以importlib直接使用

import importlib

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

You can also use importlib directly

import importlib

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

回答 11

如果不导入其“父包”,则无法可靠地检查“虚线模块”是否可导入。如此说来,对于“如何检查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

There is no way to reliably check if “dotted module” is importable without importing its parent package. Saying this, there are many solutions to problem “how to check if Python module exists”.

Below solution address the problem that imported module can raise ImportError even it exists. We want to distinguish that situation from such in which module does not exist.

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

回答 12

在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

in 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