web-dev-qa-db-ja.com

フォルダー内のすべてのモジュールをロードする方法は?

誰かがモジュールのディレクトリ全体をインポートする良い方法を提供してくれますか?
次のような構造があります。

/Foo
    bar.py
    spam.py
    eggs.py

__init__.pyを追加してfrom Foo import *を実行するだけでパッケージに変換しようとしましたが、期待どおりに機能しませんでした。

221
Evan Fosmark

現在のフォルダー内のすべてのpython(.py)ファイルをリストし、それらを__all__変数として__init__.pyに入れます

from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
341
Anurag Uniyal

次を含む__all__変数を__init__.pyに追加します。

__all__ = ["bar", "spam", "eggs"]

http://docs.python.org/tutorial/modules.html も参照してください

123
stefanw

更新:今日、おそらくimportlibを代わりに使用したいと思うでしょう。

__init__.pyを追加して、Fooディレクトリをパッケージにします。その__init__.pyに以下を追加します。

import bar
import eggs
import spam

あなたはそれを動的にしたいので(良いアイデアかもしれませんが)、すべてのpyファイルをリストdirでリストし、次のようなものでインポートします:

import os
for module in os.listdir(os.path.dirname(__file__)):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module

次に、コードから次の操作を行います。

import Foo

これでモジュールにアクセスできます

Foo.bar
Foo.eggs
Foo.spam

foo import *からなどは、名前の衝突やコードの分析を困難にするなど、いくつかの理由で良い考えではありません。

43
Lennart Regebro

ミハイルの答えを拡張すると、ハックのない方法(ファイルパスを直接処理しないなど)は次のようになります。

  1. __init__.pyの下に空のFoo/ファイルを作成します
  2. Execute
import pkgutil
import sys


def load_all_modules_from_dir(dirname):
    for importer, package_name, _ in pkgutil.iter_modules([dirname]):
        full_package_name = '%s.%s' % (dirname, package_name)
        if full_package_name not in sys.modules:
            module = importer.find_module(package_name
                        ).load_module(full_package_name)
            print module


load_all_modules_from_dir('Foo')

以下が得られます:

<module 'Foo.bar' from '/home/.../Foo/bar.pyc'>
<module 'Foo.spam' from '/home/.../Foo/spam.pyc'>
34
Luca Invernizzi

Python、ディレクトリの下にすべてのファイルを含めます。

ただ手を動かす必要のある初心者のために。

  1. フォルダー/ home/el/fooを作成し、/ home/el/fooの下にファイルmain.pyを作成します。そこにこのコードを配置します。

    from hellokitty import *
    spam.spamfunc()
    ham.hamfunc()
    
  2. ディレクトリを作成します/home/el/foo/hellokitty

  3. __init__.pyの下に/home/el/foo/hellokittyファイルを作成し、そこにこのコードを配置します。

    __all__ = ["spam", "ham"]
    
  4. 2つのpythonファイルを作成します:spam.pyham.pyの下に/home/el/foo/hellokitty

  5. Spam.py内で関数を定義します。

    def spamfunc():
      print "Spammity spam"
    
  6. Ham.py内で関数を定義します。

    def hamfunc():
      print "Upgrade from baloney"
    
  7. それを実行します:

    el@apollo:/home/el/foo$ python main.py 
    spammity spam
    Upgrade from baloney
    
20
Eric Leschinski

私は自分でこの問題にうんざりしたので、それを修正するためにautomodinitと呼ばれるパッケージを書きました。 http://pypi.python.org/pypi/automodinit/ から取得できます。

使用方法は次のとおりです。

  1. automodinitパッケージをsetup.py依存関係に含めます。
  2. 次のように__init__.pyファイルをすべて置き換えます。
 __ all__ = ["書き直します"] 
#上記の行またはこの行を変更しないでください!
 import automodinit 
 automodinit.automodinit(__ 、__ file __、globals())
 del automodinit 
#他に必要なものはすべてここに追加できます。変更はされません。

それでおしまい!これ以降、モジュールをインポートすると、__ all__がモジュール内の.py [co]ファイルのリストに設定され、入力したかのようにそれらの各ファイルもインポートされます。

for x in __all__: import x

したがって、「from M import *」の効果は「import M」と正確に一致します。

automodinitは、Zipアーカイブ内から実行できるので、Zipセーフです。

ニール

16
Niall Douglas

私はかなり古い投稿を更新していることを知っており、automodinitを使用しようとしましたが、python3のセットアッププロセスが壊れていることがわかりました。だから、ルカの答えに基づいて、私はこの問題に対してより簡単な答えを思い付きました-。

yourpackageからの__init__.pyモジュール内:

#!/usr/bin/env python
import os, pkgutil
__all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.dirname(__file__)]))

およびyourpackageの下の別のパッケージ内:

from yourpackage import *

次に、パッケージ内に配置されているすべてのモジュールがロードされ、新しいモジュールを作成すると、自動的にインポートされます。もちろん、そのようなことは慎重に行い、大きな力には大きな責任が伴います。

8
zmo

私もこの問題に遭遇し、これが私の解決策でした:

import os

def loadImports(path):
    files = os.listdir(path)
    imps = []

    for i in range(len(files)):
        name = files[i].split('.')
        if len(name) > 1:
            if name[1] == 'py' and name[0] != '__init__':
               name = name[0]
               imps.append(name)

    file = open(path+'__init__.py','w')

    toWrite = '__all__ = '+str(imps)

    file.write(toWrite)
    file.close()

この関数は、__init__.pyという名前のファイルを(提供されたフォルダーに)作成します。このファイルには、フォルダー内のすべてのモジュールを保持する__all__変数が含まれています。

たとえば、次を含むTestという名前のフォルダーがあります。

Foo.py
Bar.py

そのため、スクリプトでモジュールをインポートしたいので、次のように記述します。

loadImports('Test/')
from Test import *

これにより、Testからすべてがインポートされ、Test内の__init__.pyファイルに以下が含まれるようになります。

__all__ = ['Foo','Bar']
5
Penguinblade
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
  __import__(module)
5
Ricky

Anuragの例といくつかの修正:

import os, glob

modules = glob.glob(os.path.join(os.path.dirname(__file__), "*.py"))
__all__ = [os.path.basename(f)[:-3] for f in modules if not f.endswith("__init__.py")]
4
kzar

Anurag Uniyal answer 改善の提案あり!

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import os
import glob

all_list = list()
for f in glob.glob(os.path.dirname(__file__)+"/*.py"):
    if os.path.isfile(f) and not os.path.basename(f).startswith('_'):
        all_list.append(os.path.basename(f)[:-3])

__all__ = all_list  
4
Eduardo Lucio

これは私がこれまでに見つけた最良の方法です:

from os.path import dirname, join, isdir, abspath, basename
from glob import glob
pwd = dirname(__file__)
for x in glob(join(pwd, '*.py')):
    if not x.startswith('__'):
        __import__(basename(x)[:-3], globals(), locals())
3
Farsheed

__init__.py__all__を定義していることを確認してください。 モジュール-パッケージ ドキュメント

__init__.pyファイルは、Pythonがディレクトリをパッケージを含むものとして扱うために必要です。これは、文字列などの共通名を持つディレクトリが、後でモジュール検索パスで発生する有効なモジュールを意図せずに隠さないようにするために行われます。最も単純なケースでは、__init__.pyは単に空のファイルにできますが、パッケージの初期化コードを実行したり、後で説明する__all__変数を設定したりすることもできます。

...

唯一の解決策は、パッケージの作成者がパッケージの明示的なインデックスを提供することです。 importステートメントは次の規則を使用します。パッケージの__init__.pyコードが__all__という名前のリストを定義している場合、それはpackage import *が検出されたときにインポートされるモジュール名のリストと見なされます。パッケージの新しいバージョンがリリースされたときにこのリストを最新の状態に保つのはパッケージの作成者次第です。また、パッケージの作成者は、パッケージから*をインポートする使用法が見つからない場合、サポートしないことを決定する場合があります。たとえば、ファイルsounds/effects/__init__.pyには次のコードを含めることができます。

__all__ = ["echo", "surround", "reverse"]

これは、from sound.effects import *がサウンドパッケージの3つの名前付きサブモジュールをインポートすることを意味します。

3
gimel

標準ライブラリのpkgutilモジュールを見てください。ディレクトリに__init__.pyファイルがあれば、望みどおりに実行できます。 __init__.pyファイルは空にすることができます。

1
Mihail Mihaylov

そのためのモジュールを作成しました。これは__init__.py(またはその他の補助ファイル)に依存せず、次の2行のみを入力します。

import importdir
importdir.do("Foo", globals())

自由に再利用または貢献してください: http://gitlab.com/aurelien-lourot/importdir

1
Aurelien

importlib でインポートし、パッケージの__all__で再帰的に__init__.pyaddアクションはオプション)に追加します。

/Foo
    bar.py
    spam.py
    eggs.py
    __init__.py

# __init__.py
import os
import importlib
pyfile_extes = ['py', ]
__all__ = [importlib.import_module('.%s' % filename, __package__) for filename in [os.path.splitext(i)[0] for i in os.listdir(os.path.dirname(__file__)) if os.path.splitext(i)[1] in pyfile_extes] if not filename.startswith('__')]
del os, importlib, pyfile_extes
0
Cheney