Pythonで同じファイルに複数のクラスを入れても大丈夫ですか?
はい。哲学的な観点と実用的な観点の両方から。
Pythonでは、モジュールはメモリ内に一度存在する名前空間です。
次の仮想ディレクトリ構造があり、ファイルごとに1つのクラスが定義されているとします。
Defines
abc/
|-- callable.py Callable
|-- container.py Container
|-- hashable.py Hashable
|-- iterable.py Iterable
|-- iterator.py Iterator
|-- sized.py Sized
... 19 more
これらのクラスはすべてcollections
モジュールで利用でき、(実際には合計25個あります)標準ライブラリモジュールで定義されています_collections_abc.py
ここには_collections_abc.py
、代替の仮想ディレクトリ構造よりも優れていると思ういくつかの問題があります。
- これらのファイルはアルファベット順にソートされています。他の方法で並べ替えることもできますが、セマンティック依存性によってファイルを並べ替える機能については知りません。_collections_abcモジュールのソースは、依存関係別に整理されています。
- 病理学的でない場合、モジュールとクラス定義の両方がシングルトンであり、それぞれメモリ内で1回発生します。モジュールのクラスへの全単射マッピングがあり、モジュールが冗長になります。
- ファイルの数が増えると、クラスをさりげなく読むのが不便になります(簡単にするIDEがない限り)。ツールのない人がアクセスしにくくなります。
名前空間と組織の観点から望ましいと思う場合、クラスのグループを異なるモジュールに分割することを防ぎますか?
番号。
PythonのZenから、Pythonの成長と発展の哲学と原則を反映しています。
名前空間は素晴らしいアイデアの1つです-それらをもっとやってみましょう!
しかし、次のことも覚えておいてください。
ネストはフラットよりも優れています。
Pythonは信じられないほどクリーンで読みやすいです。読むことをお勧めします。個別のファイルにすべての個別のクラスを配置すると、読み取りが妨げられます。これは、Pythonのコア哲学に反します。標準ライブラリの構造を見てください。モジュールの大部分はパッケージではなく単一ファイルのモジュールです。慣用的なPythonコードはCPython標準ライブラリと同じスタイルで書かれていることをお伝えします。
以下は、抽象基本クラスmoduleの実際のコードです。私は、言語のさまざまな抽象型を示すためのリファレンスとして使用するのが好きです。
これらのクラスのそれぞれが個別のファイルを必要とすると言いますか?
class Hashable:
__metaclass__ = ABCMeta
@abstractmethod
def __hash__(self):
return 0
@classmethod
def __subclasshook__(cls, C):
if cls is Hashable:
try:
for B in C.__mro__:
if "__hash__" in B.__dict__:
if B.__dict__["__hash__"]:
return True
break
except AttributeError:
# Old-style class
if getattr(C, "__hash__", None):
return True
return NotImplemented
class Iterable:
__metaclass__ = ABCMeta
@abstractmethod
def __iter__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is Iterable:
if _hasattr(C, "__iter__"):
return True
return NotImplemented
Iterable.register(str)
class Iterator(Iterable):
@abstractmethod
def next(self):
'Return the next item from the iterator. When exhausted, raise StopIteration'
raise StopIteration
def __iter__(self):
return self
@classmethod
def __subclasshook__(cls, C):
if cls is Iterator:
if _hasattr(C, "next") and _hasattr(C, "__iter__"):
return True
return NotImplemented
class Sized:
__metaclass__ = ABCMeta
@abstractmethod
def __len__(self):
return 0
@classmethod
def __subclasshook__(cls, C):
if cls is Sized:
if _hasattr(C, "__len__"):
return True
return NotImplemented
class Container:
__metaclass__ = ABCMeta
@abstractmethod
def __contains__(self, x):
return False
@classmethod
def __subclasshook__(cls, C):
if cls is Container:
if _hasattr(C, "__contains__"):
return True
return NotImplemented
class Callable:
__metaclass__ = ABCMeta
@abstractmethod
def __call__(self, *args, **kwds):
return False
@classmethod
def __subclasshook__(cls, C):
if cls is Callable:
if _hasattr(C, "__call__"):
return True
return NotImplemented
だから、彼らはそれぞれ独自のファイルを持っているべきですか?
しないことを望みます。
これらのファイルは単なるコードではなく、Pythonのセマンティクスに関するドキュメントです。
平均で10〜20行です。別の10行のコードを表示するために、完全に別のファイルに移動する必要があるのはなぜですか?それは非常に非現実的です。さらに、各ファイルにほぼ同一のボイラープレートインポートがあり、コードの冗長な行が追加されます。
モジュールのリストを調べる代わりに、これらの抽象基本クラスのすべてを見つけることができる単一のモジュールがあることを知っていると非常に便利です。それらを互いにコンテキストで表示すると、それらをよりよく理解することができます。Iterator が Iterableであることがわかったら、ちらっと見て、Iterableの構成要素をすばやく確認できます。
私は時々、非常に短いクラスをいくつか持つことになります。時間の経過とともに大きくなる必要がある場合でも、ファイル内に残ります。成熟したモジュールには、1000行を超えるコードがある場合があります。しかし、ctrl-fは簡単で、一部のIDEではファイルのアウトラインを簡単に表示できます。そのため、ファイルのサイズに関係なく、探しているオブジェクトやメソッドにすばやく移動できます。
結論
Pythonのコンテキストでは、関連する、意味的に類似したクラス定義を同じファイルに保存することを希望します。ファイルが大きくなりすぎて扱いにくい場合は、再編成を検討してください。
class SomeException extends \Exception {}