Apakah boleh memiliki beberapa kelas dalam file yang sama dengan Python?
Iya. Baik dari perspektif filosofis maupun praktis.
Dalam Python, modul adalah namespace yang ada sekali di memori.
Katakanlah kita memiliki struktur direktori hipotetis berikut, dengan satu kelas ditentukan per file:
Defines
abc/
|-- callable.py Callable
|-- container.py Container
|-- hashable.py Hashable
|-- iterable.py Iterable
|-- iterator.py Iterator
|-- sized.py Sized
... 19 more
Semua kelas ini tersedia dalam collections
modul dan (pada kenyataannya, total ada 25) didefinisikan dalam modul perpustakaan standar di_collections_abc.py
Ada beberapa masalah di sini yang saya percaya membuat _collections_abc.py
lebih unggul daripada struktur direktori hipotetis alternatif.
- File-file ini disortir berdasarkan abjad. Anda dapat mengurutkannya dengan cara lain, tetapi saya tidak mengetahui fitur yang mengurutkan file berdasarkan dependensi semantik. Sumber modul _collections_abc diatur oleh ketergantungan.
- Dalam kasus-kasus non-patologis, baik modul dan definisi kelas adalah lajang, yang terjadi sekali dalam memori. Akan ada pemetaan bijective dari modul ke dalam kelas - membuat modul menjadi berlebihan.
- Meningkatnya jumlah file membuatnya kurang nyaman untuk membaca kelas secara santai (kecuali jika Anda memiliki IDE yang membuatnya sederhana) - membuatnya kurang dapat diakses oleh orang-orang tanpa alat.
Apakah Anda dicegah dari memecah kelompok kelas menjadi modul yang berbeda ketika Anda merasa diinginkan dari sudut pandang ruang nama dan organisasi?
Tidak.
Dari Zen Python , yang mencerminkan filosofi dan prinsip di mana ia tumbuh dan berkembang:
Namespaces adalah salah satu ide bagus - mari kita lakukan lebih dari itu!
Tetapi marilah kita ingat bahwa itu juga mengatakan:
Flat lebih baik daripada bersarang.
Python sangat bersih dan mudah dibaca. Ini mendorong Anda untuk membacanya. Menempatkan setiap kelas yang terpisah dalam file yang terpisah akan menghambat pembacaan. Ini bertentangan dengan filosofi inti Python. Lihatlah struktur Perpustakaan Standar , sebagian besar modul adalah modul file tunggal, bukan paket. Saya akan menyampaikan kepada Anda bahwa kode Python idiomatik ditulis dengan gaya yang sama dengan lib standar CPython.
Berikut kode aktual dari modul kelas dasar abstrak . Saya suka menggunakannya sebagai referensi untuk denotasi berbagai jenis abstrak dalam bahasa.
Apakah Anda mengatakan bahwa masing-masing kelas ini harus memerlukan file terpisah?
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
Jadi haruskah mereka masing-masing memiliki file sendiri?
Saya harap tidak.
File-file ini bukan hanya kode - mereka adalah dokumentasi tentang semantik Python.
Mereka mungkin rata-rata 10 hingga 20 baris. Mengapa saya harus pergi ke file yang benar-benar terpisah untuk melihat 10 baris kode lainnya? Itu akan sangat tidak praktis. Lebih lanjut, akan ada impor boilerplate yang hampir identik pada setiap file, menambahkan lebih banyak baris kode yang berlebihan.
Saya merasa cukup berguna untuk mengetahui bahwa ada satu modul di mana saya dapat menemukan semua Kelas Dasar Abstrak ini, daripada harus melihat daftar modul. Melihat mereka dalam konteks satu sama lain memungkinkan saya untuk lebih memahami mereka. Ketika saya melihat bahwa Iterator adalah Iterable, saya dapat dengan cepat meninjau apa yang terdiri dari Iterable dengan menoleh ke atas.
Kadang-kadang saya memiliki beberapa kelas yang sangat singkat. Mereka tetap dalam file, bahkan jika mereka perlu tumbuh lebih besar dari waktu ke waktu. Terkadang modul yang matang memiliki lebih dari 1000 baris kode. Tapi ctrl-f mudah, dan beberapa IDE membuatnya mudah untuk melihat garis besar file - jadi tidak peduli seberapa besar file, Anda dapat dengan cepat pergi ke objek atau metode apa pun yang Anda cari.
Kesimpulan
Arah saya, dalam konteks Python, adalah untuk memilih untuk menjaga definisi kelas yang terkait dan secara semantik serupa dalam file yang sama. Jika file tumbuh sangat besar sehingga menjadi berat, maka pertimbangkan reorganisasi.
class SomeException extends \Exception {}