複数のファイルをモジュール__init__.py
に整理する方法はありますか?
理由: モジュールは名前空間のレイヤーが少ないため、パッケージよりも使いやすいです。
通常、これはパッケージを作成します。問題はパッケージにあります。「パッケージをインポート」すると、空の名前空間が得られます。次に、ユーザーは "from thepackage import *" (眉をひそめる) を使用するか、何が含まれているかを正確に把握して、使用可能な名前空間に手動でプルする必要があります。
私が望むのは、ユーザーが「パッケージをインポート」して、このようにきれいな名前空間を作成し、プロジェクトに関連する関数とクラスを公開して使用することです。
current_module
\
doit_tools/
\
- (class) _hidden_resource_pool
- (class) JobInfo
- (class) CachedLookup
- (class) ThreadedWorker
- (Fn) util_a
- (Fn) util_b
- (Fn) gather_stuff
- (Fn) analyze_stuff
メンテナの仕事は、異なるファイルで同じ名前を定義しないようにすることです。これは、プロジェクトが私のように小さい場合は簡単なはずです。
from doit_stuff import JobInfo
また、クラスを含むモジュールではなく、クラスを取得できるようにするとよいでしょう。
すべてのコードが 1 つの巨大なファイルにある場合、これは簡単ですが、物事が大きくなり始めたときに整理するのが好きです。私がディスクに持っているものは、次のようなものです。
place_in_my_python_path/
doit_tools/
__init__.py
JobInfo.py
- class JobInfo:
NetworkAccessors.py
- class _hidden_resource_pool:
- class CachedLookup:
- class ThreadedWorker:
utility_functions.py
- def util_a()
- def util_b()
data_functions.py
- def gather_stuff()
- def analyze_stuff()
ファイルが巨大でナビゲートできないように、それらを分離するだけです。それらはすべて関連していますが、誰か (おそらく私) がすべてをインポートせずにクラスを自分で使用したい場合があります。
さまざまなスレッドでいくつかの提案を読みました。これを行う方法について見つけることができる各提案で何が起こるかを次に示します。
を使用しない場合、__init__.py
Python は sys.path からフォルダーに降りないため、何もインポートできません。
空白__init__.py
を使用すると、import doit_tools
何も入っていない空の名前空間になります。ファイルがインポートされないため、使用が難しくなります。
にサブモジュールをリストすると__all__
、(眉をひそめた?)from thing import *
構文を使用できますが、すべてのクラスが再び不要な名前空間バリアの背後にあります。from x import *
ユーザーは、(1)の代わりにを使用する必要があることを認識しimport x
、(2) 線幅スタイルの制約に合理的に従うことができるまで、クラスを手動で再シャッフルする必要があります。
ステートメントをに追加するfrom thatfile import X
__init__.py
と、より近くなりますが、名前空間の競合 (?) と、そこに入れたくなかったもののための追加の名前空間があります。以下の例では、次のことがわかります。
- クラス JobInfo は、名前が同じであるため、JobInfo という名前のモジュール オブジェクトを上書きしました。JobInfo の型が であるため、どういうわけか Python はこれを理解でき
<class 'doit_tools.JobInfo.JobInfo'>
ます。(doit_tools.JobInfo はクラスですが、doit_tools.JobInfo.JobInfo は同じクラスです...これは絡み合っており、非常に悪いように見えますが、何も壊れていないようです。) - 各ファイル名は doit_tools ネームスペースに入り込むため、誰かがモジュールの内容を見ている場合、より混乱を招きます。新しい名前空間を定義するのではなく、 doit_tools.utility_functions.py にいくつかのコードを保持させたい。
.
current_module
\
doit_tools/
\
- (module) JobInfo
\
- (class) JobInfo
- (class) JobInfo
- (module) NetworkAccessors
\
- (class) CachedLookup
- (class) ThreadedWorker
- (class) CachedLookup
- (class) ThreadedWorker
- (module) utility_functions
\
- (Fn) util_a
- (Fn) util_b
- (Fn) util_a
- (Fn) util_b
- (module) data_functions
\
- (Fn) gather_stuff
- (Fn) analyze_stuff
- (Fn) gather_stuff
- (Fn) analyze_stuff
また、データ抽象化クラスだけをインポートすると、「from doit_tools import JobInfo」を実行すると、予想とは異なる結果が得られます。
current_namespace
\
JobInfo (module)
\
-JobInfo (class)
instead of:
current_namespace
\
- JobInfo (class)
では、これは Python コードを整理するための間違った方法なのでしょうか? そうでない場合、関連するコードを分割してモジュールのような方法で収集する正しい方法は何ですか?
おそらく最良のシナリオは、'from doit_tools import JobInfo' を実行すると、パッケージを使用している人にとって少し混乱することでしょうか?
おそらく、コードを使用する人々が次のことを行うように、「api」と呼ばれる python ファイルですか?:
import doit_tools.api
from doit_tools.api import JobInfo
============================================
コメントへの応答の例:
Pythonパスにあるフォルダー「foo」内の次のパッケージコンテンツを取得します。
foo/__init__.py
__all__ = ['doit','dataholder','getSomeStuff','hold_more_data','SpecialCase']
from another_class import doit
from another_class import dataholder
from descriptive_name import getSomeStuff
from descriptive_name import hold_more_data
from specialcase import SpecialCase
foo/specialcase.py
class SpecialCase:
pass
foo/more.py
def getSomeStuff():
pass
class hold_more_data(object):
pass
foo/stuff.py
def doit():
print "I'm a function."
class dataholder(object):
pass
これを行う:
>>> import foo
>>> for thing in dir(foo): print thing
...
SpecialCase
__builtins__
__doc__
__file__
__name__
__package__
__path__
another_class
dataholder
descriptive_name
doit
getSomeStuff
hold_more_data
specialcase
another_class
またdescriptive_name
、名前空間の下に doit() などの余分なコピーがあります。
Data.py という名前のファイル内に Data という名前のクラスがある場合、「from Data import Data」を実行すると、名前空間の競合が発生します。これは、Data がモジュール Data 内にある現在の名前空間のクラスであるためです。現在の名前空間。(しかし、Pythonはこれを処理できるようです。)