誰かがモジュールのディレクトリ全体をインポートする良い方法を提供してくれますか?
次のような構造があります。
/Foo
bar.py
spam.py
eggs.py
__init__.py
を追加してfrom Foo import *
を実行するだけでパッケージに変換しようとしましたが、期待どおりに機能しませんでした。
現在のフォルダー内のすべての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')]
次を含む__all__
変数を__init__.py
に追加します。
__all__ = ["bar", "spam", "eggs"]
更新:今日、おそらく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 *からなどは、名前の衝突やコードの分析を困難にするなど、いくつかの理由で良い考えではありません。
ミハイルの答えを拡張すると、ハックのない方法(ファイルパスを直接処理しないなど)は次のようになります。
__init__.py
の下に空のFoo/
ファイルを作成します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'>
ただ手を動かす必要のある初心者のために。
フォルダー/ home/el/fooを作成し、/ home/el/fooの下にファイルmain.py
を作成します。そこにこのコードを配置します。
from hellokitty import *
spam.spamfunc()
ham.hamfunc()
ディレクトリを作成します/home/el/foo/hellokitty
__init__.py
の下に/home/el/foo/hellokitty
ファイルを作成し、そこにこのコードを配置します。
__all__ = ["spam", "ham"]
2つのpythonファイルを作成します:spam.py
とham.py
の下に/home/el/foo/hellokitty
Spam.py内で関数を定義します。
def spamfunc():
print "Spammity spam"
Ham.py内で関数を定義します。
def hamfunc():
print "Upgrade from baloney"
それを実行します:
el@apollo:/home/el/foo$ python main.py
spammity spam
Upgrade from baloney
私は自分でこの問題にうんざりしたので、それを修正するためにautomodinitと呼ばれるパッケージを書きました。 http://pypi.python.org/pypi/automodinit/ から取得できます。
使用方法は次のとおりです。
automodinit
パッケージをsetup.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セーフです。
ニール
私はかなり古い投稿を更新していることを知っており、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 *
次に、パッケージ内に配置されているすべてのモジュールがロードされ、新しいモジュールを作成すると、自動的にインポートされます。もちろん、そのようなことは慎重に行い、大きな力には大きな責任が伴います。
私もこの問題に遭遇し、これが私の解決策でした:
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']
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
__import__(module)
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")]
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
これは私がこれまでに見つけた最良の方法です:
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())
__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つの名前付きサブモジュールをインポートすることを意味します。
標準ライブラリのpkgutilモジュールを見てください。ディレクトリに__init__.py
ファイルがあれば、望みどおりに実行できます。 __init__.py
ファイルは空にすることができます。
そのためのモジュールを作成しました。これは__init__.py
(またはその他の補助ファイル)に依存せず、次の2行のみを入力します。
import importdir
importdir.do("Foo", globals())
自由に再利用または貢献してください: http://gitlab.com/aurelien-lourot/importdir
importlib でインポートし、パッケージの__all__
で再帰的に__init__.py
(add
アクションはオプション)に追加します。
/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