誰かがモジュールのディレクトリ全体をインポートする良い方法を教えてくれませんか?
私はこのような構造を持っています:
/Foo
bar.py
spam.py
eggs.py
__init__.py
追加して行うだけでパッケージに変換しようとしましたfrom Foo import *
が、期待どおりに機能しませんでした。
誰かがモジュールのディレクトリ全体をインポートする良い方法を教えてくれませんか?
私はこのような構造を持っています:
/Foo
bar.py
spam.py
eggs.py
__init__.py
追加して行うだけでパッケージに変換しようとしましたfrom Foo import *
が、期待どおりに機能しませんでした。
.py
現在のフォルダー内のすべての python() ファイルを一覧表示し、それらを__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"]
2017 年に更新:importlib
代わりに使用することをお勧めします。
を追加して、Foo ディレクトリをパッケージにします__init__.py
。その__init__.py
追加で:
import bar
import eggs
import spam
動的にしたいので(これは良い考えかもしれませんし、そうでないかもしれません)、すべてのpyファイルを list 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
などfrom Foo import *
は、名前の競合やコードの分析を困難にするなど、いくつかの理由からお勧めできません。
Mihailの答えを拡張すると、ハックではない方法(ファイルパスを直接処理しないなど)は次のようになります。
__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 を作成し、main.py
/home/el/foo の下にファイルを作成します。そこに次のコードを挿入します。
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__ = [「書き換えられます」] # 上の行もこの行も変更しないでください! automodinit のインポート automodinit.automodinit(__name__, __file__, globals()) del automodinit # 他に必要なものは、ここの後に置くことができます。変更されることはありません。
それでおしまい!これ以降、モジュールをインポートすると、モジュール内の .py[co] ファイルのリストに __all__ が設定され、次のように入力したかのように、これらの各ファイルもインポートされます。
for x in __all__: import x
したがって、「from M import *」の効果は「import M」と完全に一致します。
automodinit
ZIP アーカイブ内から実行できるため、ZIP セーフです。
ニール
私はかなり古い投稿を更新していることを知ってautomodinit
います. したがって、Luca の回答に基づいて、この問題に対するより簡単な回答 (.zip では機能しない可能性があります) を思いついたので、ここで共有する必要があると考えました。
__init__.py
からのモジュール内yourpackage
:
#!/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
、__init__.py
ファイルにTest
は次のものが含まれます。
__all__ = ['Foo','Bar']
#!/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
importlib
あなたが追加しなければならない唯一のものを使用することは
from importlib import import_module
from pathlib import Path
__all__ = [
import_module(f".{f.stem}", __package__)
for f in Path(__file__).parent.glob("*.py")
if "__" not in f.stem
]
del import_module, Path
これは私がこれまでに見つけた最良の方法です:
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())
from . import *
十分でない場合、これはted による回答の改善です。具体的には、__all__
このアプローチでは を使用する必要はありません。
"""Import all modules that exist in the current directory."""
# Ref https://stackoverflow.com/a/60861023/
from importlib import import_module
from pathlib import Path
for f in Path(__file__).parent.glob("*.py"):
module_name = f.stem
if (not module_name.startswith("_")) and (module_name not in globals()):
import_module(f".{module_name}", __package__)
del f, module_name
del import_module, Path
module_name not in globals()
モジュールが既にインポートされている場合、モジュールの再インポートを回避することを意図していることに注意してください。
あなたが__init__.py
定義していることを確認してください__all__
。モジュール-パッケージドキュメントによると
これらの
__init__.py
ファイルは、Pythonがディレクトリをパッケージを含むものとして扱うようにするために必要です。これは、文字列などの一般的な名前のディレクトリが、後でモジュール検索パスで発生する有効なモジュールを意図せずに非表示にするのを防ぐために行われます。最も単純なケースで__init__.py
は、空のファイルにすることもできますが、パッケージの初期化コードを実行したり__all__
、後で説明する変数を設定したりすることもできます。..。
唯一の解決策は、パッケージの作成者がパッケージの明示的なインデックスを提供することです。importステートメントは次の規則を使用します。パッケージの
__init__.py
コードがという名前のリストを定義している場合__all__
、それはfrom packageimport*が検出されたときにインポートする必要があるモジュール名のリストと見なされます。パッケージの新しいバージョンがリリースされたときにこのリストを最新の状態に保つのは、パッケージの作成者の責任です。パッケージの作成者は、パッケージから*をインポートする用途が見当たらない場合は、サポートしないことを決定する場合もあります。たとえば、ファイルsounds/effects/__init__.py
には次のコードが含まれている可能性があります。
__all__ = ["echo", "surround", "reverse"]
これは
from sound.effects import *
、サウンドパッケージの3つの名前付きサブモジュールをインポートすることを意味します。
標準ライブラリのpkgutilモジュールを見てください。__init__.py
ディレクトリにファイルがある限り、それはあなたが望むことを正確に行うことを可能にします。__init__.py
ファイルは空にすることができます。
ネストされたディレクトリ構造がありました。つまり、メイン ディレクトリ内に Python モジュールを含む複数のディレクトリがありました。
次のスクリプトを__init__.py
ファイルに追加して、すべてのモジュールをインポートしました
import glob, re, os
module_parent_directory = "path/to/the/directory/containing/__init__.py/file"
owd = os.getcwd()
if not owd.endswith(module_parent_directory): os.chdir(module_parent_directory)
module_paths = glob.glob("**/*.py", recursive = True)
for module_path in module_paths:
if not re.match( ".*__init__.py$", module_path):
import_path = module_path[:-3]
import_path = import_path.replace("/", ".")
exec(f"from .{import_path} import *")
os.chdir(owd)
おそらくこれを達成するための最良の方法ではありませんが、他に何も機能させることができませんでした。