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 {}
Saat menyusun aplikasi Anda dengan Python, Anda perlu berpikir dalam hal paket dan modul.
Modul adalah tentang file yang sedang Anda bicarakan. Tidak masalah untuk memiliki banyak kelas dalam modul yang sama. Tujuannya adalah bahwa semua kelas dalam modul yang sama harus melayani tujuan / logika yang sama. Jika modul terlalu lama maka pikirkan untuk membagi kembali dengan mendesain ulang logika Anda.
Jangan lupa membaca dari waktu ke waktu tentang Proposal Peningkatan Indeks Python .
sumber
Jawaban sebenarnya untuk ini adalah umum, dan tidak tergantung pada bahasa yang digunakan: Apa yang seharusnya ada dalam file tidak terutama tergantung pada berapa banyak kelas yang didefinisikannya. Itu tergantung pada keterhubungan logis, dan pada kompleksitas. Titik.
Jadi, jika Anda memiliki beberapa kelas yang sangat kecil yang sangat saling berhubungan, mereka harus dibundel ke dalam file yang sama. Anda harus membagi kelas jika tidak terhubung dengan erat ke kelas lain, atau jika terlalu rumit untuk disertakan dengan kelas lain.
Yang mengatakan, aturan satu-kelas-per-file biasanya heuristik yang baik. Namun, ada pengecualian penting: Kelas pembantu kecil yang benar-benar hanya detail implementasi dari kelas pengguna tunggal umumnya harus digabungkan ke dalam file kelas pengguna itu. Demikian juga, jika Anda memiliki tiga kelas
vector2
,,vector3
danvector4
, ada kemungkinan kecil alasan untuk mengimplementasikannya dalam file terpisah.sumber