Pertimbangkan kelas berikut:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
Rekan kerja saya cenderung mendefinisikannya seperti ini:
class Person:
name = None
age = None
def __init__(self, name, age):
self.name = name
self.age = age
Alasan utama untuk ini adalah bahwa editor pilihan mereka menunjukkan properti untuk pelengkapan otomatis.
Secara pribadi, saya tidak suka yang terakhir, karena tidak masuk akal bahwa kelas memiliki sifat-sifat tersebut None
.
Yang mana yang akan menjadi praktik yang lebih baik dan untuk alasan apa?
__init__
sudah menyediakan autocompletion dll. Juga, menggunakanNone
mencegah IDE untuk menyimpulkan jenis atribut yang lebih baik, jadi lebih baik menggunakan default yang masuk akal sebagai gantinya (ketika mungkin).typing
modul, yang memungkinkan Anda untuk memberikan petunjuk kepada IDE dan linter, jika hal semacam itu menggelitik keinginan Anda ...self
. Bahkan jikaself.name
atauself.age
tidak ditugaskan di__init__
mereka tidak akan muncul dalam contohself
, mereka hanya muncul di kelasPerson
.Jawaban:
Saya menyebut praktik buruk yang terakhir di bawah aturan "ini tidak melakukan apa yang Anda pikirkan".
Posisi rekan kerja Anda dapat ditulis ulang sebagai: "Saya akan membuat sekelompok variabel quasi-global kelas-statis yang tidak pernah diakses, tetapi yang mengambil ruang di berbagai tabel namespace kelas (
__dict__
), hanya untuk membuat IDE saya lakukan sesuatu."sumber
-OO
,, untuk beberapa yang membutuhkannya.1. Buat kode Anda mudah dimengerti
Kode dibaca lebih sering daripada tertulis. Jadikan tugas pengelola kode Anda lebih mudah (mungkin juga Anda sendiri tahun depan).
Saya tidak tahu tentang aturan keras apa pun, tetapi saya lebih suka memiliki keadaan instance di masa depan yang dinyatakan dengan jelas. Menabrak dengan
AttributeError
sudah cukup buruk. Tidak melihat dengan jelas siklus hidup atribut instance lebih buruk. Jumlah senam mental yang diperlukan untuk mengembalikan kemungkinan urutan panggilan yang mengarah pada atribut yang ditugaskan dapat dengan mudah menjadi non-sepele, yang menyebabkan kesalahan.Jadi saya biasanya tidak hanya mendefinisikan segala sesuatu di konstruktor, tetapi juga berusaha untuk menjaga jumlah atribut yang dapat diubah ke minimum.
2. Jangan mencampur anggota tingkat kelas dan tingkat kejadian
Apa pun yang Anda tetapkan tepat di dalam
class
deklarasi adalah milik kelas dan dibagikan oleh semua instance kelas. Misalnya ketika Anda mendefinisikan fungsi di dalam kelas, itu menjadi metode yang sama untuk semua instance. Hal yang sama berlaku untuk anggota data. Ini sama sekali berbeda dengan atribut instance yang biasanya Anda definisikan__init__
.Anggota data tingkat kelas paling berguna sebagai konstanta:
sumber
self
dan tidak perluself
dilewatkan, sementara metode level kelas tidak terikat dan fungsi polos seperti yang terlihat padadef
waktu, dan menerima instance sebagai argumen pertama. Jadi ini adalah hal yang berbeda.AttributeError
sinyal itu bagus daripada bug. Jika tidak, Anda akan menelan Tidak Ada dan mendapatkan hasil yang tidak berarti. Khusus penting dalam kasus yang dihadapi, di mana atribut didefinisikan dalam__init__
, sehingga atribut yang hilang (tetapi ada di tingkat kelas) hanya dapat disebabkan oleh warisan kereta.None
dan nilai ini tidak masuk akal pada saat konstruksi contoh, Anda memiliki masalah dalam arsitektur Anda dan harus memikirkan kembali siklus hidup dari nilai atribut atau nilai awalnya. Perhatikan bahwa dengan mendefinisikan atribut Anda lebih awal, Anda dapat mendeteksi masalah seperti itu bahkan sebelum Anda menulis seluruh kelas, apalagi menjalankan kode.Secara pribadi saya mendefinisikan anggota dalam metode __ init __ (). Saya tidak pernah berpikir untuk mendefinisikan mereka di bagian kelas. Tetapi apa yang selalu saya lakukan: Saya init semua anggota dalam metode __ init__, bahkan mereka yang tidak diperlukan dalam metode __ init__.
Contoh:
Saya pikir penting untuk mendefinisikan semua anggota di satu tempat. Itu membuat kode lebih mudah dibaca. Apakah itu di dalam __ init __ () atau di luar, tidak begitu penting. Tetapi penting bagi sebuah tim untuk berkomitmen pada gaya pengkodean yang kurang lebih sama.
Oh, dan Anda mungkin memperhatikan bahwa saya pernah menambahkan awalan "_" ke variabel anggota.
sumber
_
: Untuk menunjukkan bahwa itu pribadi! (Mengapa begitu banyak orang di utas ini membingungkan atau Python setengah membingungkan dengan bahasa lain?)Ini adalah praktik yang buruk. Anda tidak perlu nilai-nilai itu, mereka mengacaukan kode, dan mereka dapat menyebabkan kesalahan.
Mempertimbangkan:
sumber
Saya akan pergi dengan "sedikit seperti dokumen, lalu" dan menyatakan ini tidak berbahaya, selama itu selalu
None
, atau kisaran sempit dari nilai-nilai lain, semua tidak berubah.Itu berbau atavisme, dan lampiran berlebihan untuk bahasa yang diketik secara statis. Dan tidak ada gunanya sebagai kode. Tetapi memiliki tujuan kecil yang tersisa, dalam dokumentasi.
Ini mendokumentasikan apa nama yang diharapkan, jadi jika saya menggabungkan kode dengan seseorang dan salah satu dari kami memiliki 'nama pengguna' dan nama_pengguna lainnya, ada petunjuk bagi manusia bahwa kami telah berpisah dan tidak menggunakan variabel yang sama.
Memaksa inisialisasi penuh sebagai kebijakan mencapai hal yang sama dengan cara yang lebih Pythonic, tetapi jika ada kode aktual dalam
__init__
, ini menyediakan tempat yang lebih jelas untuk mendokumentasikan variabel yang digunakan.Jelas masalah BESAR di sini adalah bahwa ia menggoda orang untuk menginisialisasi dengan nilai selain
None
, yang bisa buruk:meninggalkan jejak global dan tidak membuat turunan untuk x.
Tapi itu lebih merupakan kekhasan dalam Python secara keseluruhan daripada dalam praktik ini, dan kita seharusnya sudah paranoid tentang hal itu.
sumber