パッケージ内のPythonモジュールの名前をリストする標準的な方法はありますか?


100

を使用せずにパッケージ内のすべてのモジュールの名前を一覧表示する簡単な方法はあり__all__ますか?

たとえば、次のパッケージがあるとします。

/testpkg
/testpkg/__init__.py
/testpkg/modulea.py
/testpkg/moduleb.py

私はこのようなことをするための標準的な方法または組み込みの方法があるかどうか疑問に思っています:

>>> package_contents("testpkg")
['modulea', 'moduleb']

手動のアプローチは、パッケージのディレクトリを見つけるためにモジュール検索パスを反復することです。次に、そのディレクトリ内のすべてのファイルを一覧表示し、一意の名前が付けられたpy / pyc / pyoファイルを除外して、拡張子を取り除き、そのリストを返すことができます。しかし、これは、モジュールインポートメカニズムがすでに内部で実行していることに対してかなりの量の作業のようです。その機能はどこかで公開されていますか?

回答:


22

多分これはあなたが探していることをするでしょうか?

import imp
import os
MODULE_EXTENSIONS = ('.py', '.pyc', '.pyo')

def package_contents(package_name):
    file, pathname, description = imp.find_module(package_name)
    if file:
        raise ImportError('Not a package: %r', package_name)
    # Use a set because some may be both source and compiled.
    return set([os.path.splitext(module)[0]
        for module in os.listdir(pathname)
        if module.endswith(MODULE_EXTENSIONS)])

1
init .pyは実際にはパッケージの一部ではないので、「and module!= " init .py」」を最後の「if」に追加します。.pyoも有効な拡張子です。それとは別に、imp.find_moduleを使用することは非常に良いアイデアです。これが正解だと思います。
DNS、

3
私は同意しません-initを直接インポートできるので、なぜ特別なケースですか?ルールを破るのに十分なほど特別なことではありません。;-)
cdleary 2009年

6
おそらくimp.get_suffixes()手書きのリストの代わりに使用する必要があります。
itsadok 2009年

3
また、ノートこれはのようなサブパッケージでは動作しないことxml.sax
itsadok

1
これは本当に悪い方法です。ファイル名拡張子からモジュールが何であるかを確実に判断することはできません。
WIM

188

使い方のpython2.3をし、上記の、あなたも使用できるpkgutilモジュールを:

>>> import pkgutil
>>> [name for _, name, _ in pkgutil.iter_modules(['testpkg'])]
['modulea', 'moduleb']

編集:パラメータはモジュールのリストではなく、パスのリストであるため、次のようにすることをお勧めします。

>>> import os.path, pkgutil
>>> import testpkg
>>> pkgpath = os.path.dirname(testpkg.__file__)
>>> print [name for _, name, _ in pkgutil.iter_modules([pkgpath])]

15
これは文書化されていませんが、これを行う最も適切な方法のようです。私がメモを追加しても構わないと思います。
itsadok 2009年

13
pkgutil実際にはpython2.3以降にあります。また、しばらくはpkgutil.iter_modules()そこにある、再帰的に動作しませんpkgutil.walk_packages()これは、同様ます再帰します。このパッケージへのポインタをありがとう。
Sandip Bhattacharya、2012年

なぜiter_modules絶対インポートでは機能しないのa.b.testpkgですか?それは私に与えています[]
フセイン

私はあなたのEDITを見落とし:(申し訳ありませんが、私は第二のスニペットを踏襲した後、それは動作します。。。
フセイン

1
pkgutil.walk_packages()再帰を確認できません。と同じ出力が得られるpkgutil.iter_modules()ので、答えは不完全だと思います。
rwst

29
import module
help(module)

2
ヘルプはヘルプテキストの下部にパッケージの内容を一覧表示しますが、質問はこれを行う方法の行に沿っています:f(package_name)=> ["module1_name"、 "module2_name"]。ヘルプから返された文字列を解析できたと思いますが、それはディレクトリをリストするよりも回り道のようです。
DNS

1
@DNS:help()文字列を返しません。
Junuxx 2013年

これは遠回りの方法であることに同意しますが、それがどのようにhelp()機能するかを確認するためにうさぎの穴を降りました。とにかく、組み込みpydocモジュールは、help()ページ分割する文字列を吐き出すのに役立ちますimport pydoc; pydoc.render_doc('mypackage')
sraboy

7

私が見落としているのか、答えが古くなっているのかはわかりませんが、

user815423426によって述べられているように、これはライブオブジェクトに対してのみ機能し、リストされたモジュールは以前にインポートされたモジュールのみです。

パッケージ内のモジュールのリストは、inspectを使用すると本当に簡単に見えます。

>>> import inspect, testpkg
>>> inspect.getmembers(testpkg, inspect.ismodule)
['modulea', 'moduleb']

import = import __( 'myproj.mymod.mysubmod')m = inspect.getmembers(i、inspect.ismodule)を入れましたが、インポートされたパスは〜/ myproj / __ init .pyであり、mは(mymod、 '〜 /myproj/mymod/__init__.py ')
hithwen

1
@hithwenコメントに質問を投稿しないでください。特に直接関係がない場合は特に注意してください。良いサマリア人であること:を使用してくださいimported = import importlib; importlib.import_module('myproj.mymod.mysubmod')__import__トップレベルのモジュールをインポートしますドキュメントを参照してください
siebz0r 2013

うーん、これは有望ですが、私にはうまくいきません。実行するimport inspect, mypackageと、inspect.getmembers(my_package, inspect.ismodule)確かにさまざまなモジュールが含まれているにもかかわらず、空のリストが表示されます。
Amelio Vazquez-Reina

1
実際のところ、これは私import my_package.fooだけimport mypackageでなく、私だけが機能するようで、その場合はが返されますfoo。しかし、これは目的に
反します

3
@ user815423426あなたは絶対に正しいです;-)私は何かを見落としていたようです。
siebz0r 2013年

2

これは、Python 3.6以降で動作する再帰バージョンです。

import importlib.util
from pathlib import Path
import os
MODULE_EXTENSIONS = '.py'

def package_contents(package_name):
    spec = importlib.util.find_spec(package_name)
    if spec is None:
        return set()

    pathname = Path(spec.origin).parent
    ret = set()
    with os.scandir(pathname) as entries:
        for entry in entries:
            if entry.name.startswith('__'):
                continue
            current = '.'.join((package_name, entry.name.partition('.')[0]))
            if entry.is_file():
                if entry.name.endswith(MODULE_EXTENSIONS):
                    ret.add(current)
            elif entry.is_dir():
                ret.add(current)
                ret |= package_contents(current)


    return ret

os.scandir結果のエントリを直接反復処理する代わりに、コンテキストマネージャとして使用する利点は何ですか?
-monkut

1
参照の@monkut docs.python.org/3/library/os.html#os.scandirことを確認するために、コンテキストマネージャとしてそれを使用することをお勧めしcloseますが任意の保持していたリソースが解放されていることを確認することで行われたときに呼び出されます。
tacaswell

これは機能せreず、代わりにすべてのパッケージがリストされますがre.、すべてに追加されます
Tushortz

1

cdlearyの例に基づいて、すべてのサブモジュールの再帰的なバージョンリストパスを次に示します。

import imp, os

def iter_submodules(package):
    file, pathname, description = imp.find_module(package)
    for dirpath, _, filenames in os.walk(pathname):
        for  filename in filenames:
            if os.path.splitext(filename)[1] == ".py":
                yield os.path.join(dirpath, filename)


0

(コマンドプロンプトから)Pythonコードの外でパッケージに関する情報を表示したい場合は、pydocを使用できます。

# get a full list of packages that you have installed on you machine
$ python -m pydoc modules

# get information about a specific package
$ python -m pydoc <your package>

pydocと同じ結果になりますが、ヘルプを使用してインタープリター内で

>>> import <my package>
>>> help(<my package>)

-2
def package_contents(package_name):
  package = __import__(package_name)
  return [module_name for module_name in dir(package) if not module_name.startswith("__")]

これは、パッケージではなくモジュールでのみ機能します。Pythonのloggingパッケージで試して、私の意味を確認してください。Loggingには、ハンドラーと構成の2つのモジュールが含まれています。コードは66項目のリストを返しますが、これらの2つの名前は含まれていません。
DNS

-3

dir(モジュール)を印刷する


1
既にインポートされているモジュールの内容が一覧表示されます。まだインポートされていないパッケージの内容を一覧表示する方法を探しています。これは、「from x import *」のように、すべてが指定されていない場合と同じです。
DNS

from x import *は、最初にモジュールをインポートしてから、すべてを現在のモジュールにコピーします。
セブ

Windowsでは大文字と小文字が区別されるため、「from x import *」は実際にはパッケージのサブモジュールをインポートしないことに気付きました。私はそれを自分がやりたいことの例としてのみ含めました。混乱を避けるために、質問からそれを編集しました。
DNS、

これは、サブモジュールのみのリストではなく、すでにインポートされたオブジェクトのすべての属性をリストします。そのため、質問の答えにはなりません。
bignose、2010年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.