Pythonライブラリでは、さまざまなオブジェクトがPythonクラスとして表されます。ただし、ユーザーがそれらのクラスのインスタンスを直接作成することは想定されていません。代わりに、それらを作成するための便利な関数のセットがあるので、私のモジュールソースは現在次のようになります。
_class Foo:
pass
class Bar:
pass
def create_object(x):
# ... either return a Foo or a Bar,
# depending on the value of x.
_
問題は、これがインターフェースを実装から適切に分離しないことです。クラスを少し隠して欲しいです。それらを完全に非表示にするのではなく、それらの___init__
_関数がパブリックインターフェイスの一部ではないことをもう少し明確にします。
ユーザーの観点からは、クラスを別のモジュールに配置するのが理にかなっているようです。したがって、myModule.make_object(10)
を呼び出して、タイプ_myModule.objects.Foo
_のオブジェクトを取得します。
ただし、読みやすさ/保守性の観点からは、モジュールの名前空間がファイルに関連付けられているため、頭痛の種になります。1つはクラスを含み、もう1つはクラスを含む相互参照を維持する必要があります。それらを作成する関数。これは私のプロジェクトにとって論理的な構造ではないので、避けたいと思います。
編集:明確にするために、循環依存関係について話しているのではありません-クラスFoo
およびBar
は_create_object
_を呼び出しません。ファクトリ関数が1つのファイルにあり、クラスが別のファイルにある場合、コードがどのように機能するかを理解するために、future-meはまず1つのファイルで_create_object
_を検索し、次に別のファイルで呼び出すコンストラクター。多くのクラスと多くのファクトリ関数があるので、これはたくさん行われなければならないでしょう。私はこの種のジャンプが短期的な記憶に不必要に負荷をかけていることを発見し、一般的に物事を理解するのを難しくします。正方形と長方形のクラス、正方形と長方形を作成する関数、円と楕円のクラス、それらを作成する関数などを含む単一のファイルを用意したいと思います。
だから私の質問は:
(1)objects
モジュールを個別のファイルなしで作成する方法はありますか? _types.ModuleType
_をインスタンス化してモジュールを作成できることはわかっていますが、クラスを新しいモジュールに宣言する方法を理解できません。
(2)(1)を解決できると仮定すると、それは実際に賢明なことでしょうか?
(3)それとも私はこれをどういうわけか間違った方法で考えていますか? Pythonでこの問題を解決する標準的な方法は何でしょうか?
これにより相互参照が発生する場合(およびおそらく循環インポートで解決される場合)、クラスをビルダーから分離することは賢明ではないと思います。あなたの目的が単に公開または非公開であることを意味するものを公開することである場合、それを明示するより良い方法があります。
私が考えることができる最も簡単なことは、次のようにモジュールを構造化することです:
mylib
|-- __init__.py
|-- objects.py
ここで、objects.py
はまさにあなたが既に持っているものであり、__init__.py
は単に次のことを行います。
from .objects import create_object
したがって、ユーザーがmylib
をインポートする場合、その中で使用できるシンボルはパブリックAPIのみです。
create_object
のような命名規則に従って多くの関数がある場合、__init__.py
に次のようなものを含めることにより、__init__.py
へのインポートを自動化できます。
import objects
import inspect
import sys
current_module = sys.modules[__name__]
create_functions = [(name, func) for (name, func) in inspect.getmembers(objects, inspect.isfunction)
if name.startswith('create_')]
for name, func in create_functions:
setattr(current_module, name, func)
簡単な方法は、_Foo
および_Bar
クラスを宣言することです。
あなたはそれらをプライベートとしてマークします、その意図はそれらをモジュールの外ではなくモジュールの内部で使用することです。