インポートせずにPythonモジュールが存在するかどうかを確認する方法


179

インポートせずに、Pythonモジュールが存在するかどうかを知る必要があります。

存在しない可能性のあるもの(私が望んでいるものではないもの)のインポート:

try:
    import eggs
except ImportError:
    pass

4
興味があるのですが、インポートを使用することの欠点は何ですか?
チャック

15
モジュールに副作用がある場合、インポートを呼び出すと望ましくない結果が生じる可能性があります。したがって、最初に実行するファイルのバージョンを確認したい場合は、以下の回答で確認し、後でインポートすることができます。副作用のあるモジュールを作成することは良い考えではありませんが、私たちは皆大人であり、コーディングの危険性について自分で決定することができます。
yarbelk 2014


1
@ArtOfWarfare私は閉じていることを質問あなたがの重複としてリンクされ、この 1。この質問はより明確であり、ここで提案されている解決策はそこにリストされている他のすべてのものよりも優れているからです。私は、このより良い解決策への回答を求めている人には、人を遠ざけるよりも指摘したいと思います。
バクリウ14

7
@Chuckさらに、モジュールは存在する可能性がありますが、それ自体にインポートエラーが含まれている可能性があります。上記のコードのようにImportErrorsをキャッチすると、実際には存在するがエラーがある場合に、モジュールが存在しないことを示す可能性があります。
Michael Barton

回答:


198

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

これを回避するためのコメントを歓迎します

謝辞

  • importlibの@rvighne
  • @ lucas-guido for python3.3 + depricating find_loader
  • python2.7でのpkgutils.find_loader動作の@enpenax

3
これはトップレベルのモジュールでのみ機能し、では機能しませんeggs.ham.spam
hemflit 2013年

3
検索したい場合は@hemflit spameggs.hamあなたが使用するimp.find_module('spam', ['eggs', 'ham'])
gitaarik

5
1、しかしimpれる非推奨の賛成でimportlib3 Pythonで
rvighne

4
インポートされたモジュールに実際の「ImportError」が含まれている場合はどうなりますか。それが私に起こっていたのです。その後、モジュールは存在しますが、「見つかりません」。
enpenax 14

1
1年後、ちょうど上で述べたのと同じ問題に遭遇し、Python 2の解決策を模索していました。pkgutil.find_loader("my.package.module")パッケージ/モジュールが存在する場合と存在しNoneない場合は、ローダーを返します。ImportErrorをマスキングして昨日のxPを狂わせたので、Python 2の回答を更新してください
enpenax 2015年

13

yarbelkの応答を使用した後、インポートする必要がないためにこれを作成しましたìmp

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

settings.pyたとえばDjangoで役立ちます。


4
このマスクはモジュール内のインポートエラーであり、エラーの特定が非常に難しくなるため、私は反対票を投じました。
enpenax

1
反対票を投じるのは悪い考えですが、「常にキャッチされたエラーをログに記録する」のがよいでしょう。これはあなたがそれを望む方法を書いた後の例です。
ズールー

2
インポートされたモジュールが1行目でImportErrorで失敗し、try catchがそれを黙って失敗させた場合、どのようにエラーをログに記録しますか?
enpenax 2015

私は実際にマスキングインポートエラーの問題に遭遇しましたが、それは悪かった(テストに合格しなかったはずです!)。
デビッドギヴン

誰かが別のモジュールにモンキーパッチをトリガするために、そのエラーを使用していた私はどこだったこと...それに走った狂気見つける
yarbelk

13

Python 3> = 3.6:ModuleNotFoundError

ModuleNotFoundError導入されたのpython 3.6およびこの目的のために使用することができます

try:
    import eggs
except ModuleNotFoundError:
    # Error handling
    pass

このエラーは、モジュールまたはその親の1つが見つからない場合に発生します。そう

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


1
存在する場合はパッケージをインポートするため、これは質問に答えません
divenex

11

ImportErrorに依存しないPython 2

現在の答えが更新されるまで、これが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がキャッチされ、物事が静かに失敗することを理解するためにかなりの量のバックトラックを必要とします。


不明確だったかもしれませんが、最初のコードブロック以外はすべて依存していませImportErrorん。不明な場合は編集してください。
ヤーベルク

最初の2つのPython 2の例でImportErrorキャッチを使用しているのがわかります。では、なぜそこにいるのですか?
enpenax

3
mod == 'not_existing_package.mymodule'の場合、これはImportErrorをスローします。以下の
MarcinRaczyński

1
もちろん、インポートエラーがスローされます。モジュールが存在しない場合は、インポートエラーがスローされるはずです。そうすれば、必要に応じてそれをキャッチできます。他のソリューションの問題は、他のエラーをマスクすることです。
enpenax 2016年

Try / Exceptは、ログに記録したり、物事を確認したりしてはならないという意味ではありません。基礎となるトレースバックを完全にキャッチし、必要なことを何でも実行できます。
ズールー

8

go_asのワンライナーとしての答え

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

6

コマンドラインからモジュールがロードされているかどうかを確認する方法を探しているときにこの質問に出くわし 、私の後に来るものと同じものを探している私の考えを共有したいと思います:

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ドキュメントが見つかりません

そして終了します。


5

たとえば、pkgutil関数の 1つを使用します。

from pkgutil import iter_modules

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


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ですので。したがって、インポートを知っている限り、これでうまくいくはずです。


3

私はこのヘルパー関数を書きました:

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

2

importlib直接使用することもできます

import importlib

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

これには実際にそれをインポートする問題があります。副作用とすべて
yarbelk

2

親パッケージをインポートせずに「ドット付きモジュール」がインポート可能かどうかを確実にチェックする方法はありません。これを言うと、「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

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

これは、pythonをプログラミングするときの私の標準的な質問を満たします:WWDD(Djangoはどうしますか?)そして私はそこを見る必要があります
yarbelk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.