Saya melihat pola suka
def __init__(self, x, y, z):
...
self.x = x
self.y = y
self.z = z
...
cukup sering, sering dengan lebih banyak parameter. Apakah ada cara yang baik untuk menghindari pengulangan yang membosankan seperti ini? Haruskah kelas mewarisi dari namedtuple
gantinya?
__slots__
untuk tujuan itu ; itu agak unpythonic (lebih verbose untuk mendapatkan penghematan memori), tapi saya suka sebagian besar untuk menghindari risiko auto-vivifying atribut yang sama sekali baru jika saya mengetik nama.ini <shortcut> x, y, z): <shortcut>
dan selesai.Jawaban:
Sunting: Jika Anda memiliki python 3.7+ gunakan dataclasses
Solusi dekorator yang menyimpan tanda tangan:
sumber
signature
Penafian: Tampaknya beberapa orang khawatir tentang menghadirkan solusi ini, jadi saya akan memberikan penafian yang sangat jelas. Anda sebaiknya tidak menggunakan solusi ini. Saya hanya menyediakannya sebagai informasi, sehingga Anda tahu bahasanya mampu melakukannya. Jawaban lainnya hanya menunjukkan kemampuan bahasa, bukan mendukung menggunakannya dengan cara ini.
Tidak ada yang salah dengan menyalin parameter ke atribut secara eksplisit. Jika Anda memiliki terlalu banyak parameter dalam ctor, terkadang dianggap sebagai bau kode dan mungkin Anda harus mengelompokkan params ini menjadi objek yang lebih sedikit. Di lain waktu, itu perlu dan tidak ada yang salah dengan itu. Bagaimanapun, melakukannya secara eksplisit adalah cara untuk melakukannya.
Namun, karena Anda bertanya BAGAIMANA itu bisa dilakukan (dan bukan apakah itu harus dilakukan), maka salah satu solusinya adalah ini:
sumber
self.__dict__.update(kwargs)
mungkin sedikit lebih pythonicA.__init__
sebenarnya mengharapkan, dan tidak ada kesalahan memeriksa nama argumen yang salah ketik.kwargs
membiarkan Anda membuka setara dengan serangan injeksi SQL. Jika objek Anda memiliki metode yang dinamaimy_method
dan Anda meneruskan argumen yang dinamaimy_method
ke konstruktor, makaupdate()
kamus, Anda hanya menimpa metode tersebut.Seperti yang telah disebutkan orang lain, pengulangan itu tidak buruk, tetapi dalam beberapa kasus, namesupuple sangat cocok untuk jenis masalah ini. Ini menghindari penggunaan lokal () atau kwargs, yang biasanya merupakan ide yang buruk.
Saya telah menemukan penggunaan terbatas untuk itu, tetapi Anda dapat mewarisi nama named seperti dengan objek lain (contoh lanjutan):
sumber
properties
metode Anda dapat ditulis sebagai adilreturn tuple(self)
, yang lebih dapat dipertahankan jika di masa mendatang lebih banyak bidang ditambahkan ke definisi nameduple.XYZ = namedtuple("XYZ", "x y z")
berfungsi.namedtuple
s untuk tujuan yang tepat ini, terutama dalam kode matematika di mana fungsi mungkin sangat parametris dan memiliki banyak koefisien yang hanya masuk akal bersama.namedtuple
adalah mereka hanya baca. Anda tidak bisa melakukanabc.x += 1
hal seperti itu.eksplisit lebih baik daripada implisit ... jadi pastikan Anda bisa membuatnya lebih ringkas:
Pertanyaan yang lebih baik adalah seharusnya Anda?
... yang mengatakan jika Anda ingin nama tuple saya akan merekomendasikan menggunakan namatuple (ingat tuple memiliki kondisi tertentu yang menyertainya) ... mungkin Anda ingin memesan atau bahkan hanya perintah ...
sumber
if k != "self":
bisa diubah menjadiif v is not self:
, tes identitas murah, daripada perbandingan string. Saya kira secara teknis__init__
bisa disebut kedua kalinya setelah konstruksi danself
dinyatakan sebagai argumen berikutnya, tetapi saya benar-benar tidak ingin berpikir monster seperti apa yang akan melakukan itu. :-)locals
:set_fields_from_locals(locals())
. Maka itu tidak lebih dari solusi berbasis dekorator yang lebih ajaib.Untuk memperluas
gruszczy
jawaban s, saya telah menggunakan pola seperti:Saya suka metode ini karena:
super().__init(...)
)X.__init__
Sebelum Python 3.6, ini tidak memberikan kontrol atas urutan atribut ditetapkan, yang bisa menjadi masalah jika beberapa atribut adalah properti dengan setter yang mengakses atribut lainnya.
Mungkin bisa ditingkatkan sedikit, tapi saya satu-satunya pengguna kode saya sendiri jadi saya tidak khawatir tentang segala bentuk sanitasi input. Mungkin
AttributeError
akan lebih tepat.sumber
Anda juga bisa:
Tentu saja, Anda harus mengimpor
inspect
modul.sumber
Ini adalah solusi tanpa impor tambahan.
Fungsi pembantu
Fungsi pembantu kecil membuatnya lebih nyaman dan dapat digunakan kembali:
Aplikasi
Anda perlu menyebutnya dengan
locals()
:Uji
Keluaran:
Tanpa berubah
locals()
Jika Anda tidak ingin mengubah,
locals()
gunakan versi ini:sumber
locals()
tidak boleh dimodifikasi (ini dapat memengaruhi juru bahasa, dalam kasus Anda, menghapusself
dari ruang lingkup fungsi panggilan)self
masih tersedia di__init__
.Pustaka menarik yang menangani ini (dan menghindari banyak pelat ketel lainnya) adalah attrs . Contoh Anda, misalnya, dapat direduksi menjadi ini (anggap kelasnya dipanggil
MyClass
):Anda bahkan tidak perlu
__init__
metode lagi, kecuali itu melakukan hal-hal lain juga. Ini pengantar yang bagus dari Glyph Lefkowitz .sumber
attr
dibuat redundandataclasses
?$ 0,02 saya Sangat dekat dengan jawaban Joran Beasley, tetapi lebih elegan:
Selain itu, jawaban Mike Müller (yang terbaik untuk seleraku) dapat dikurangi dengan teknik ini:
Dan telepon
auto_init(locals())
dari Anda__init__
sumber
locals()
tidak boleh dimodifikasi (perilaku tidak terdefinisi)Ini adalah cara alami untuk melakukan sesuatu dengan Python. Jangan mencoba untuk menciptakan sesuatu yang lebih pintar, itu akan mengarah pada kode yang terlalu pintar sehingga tidak seorang pun di tim Anda akan mengerti. Jika Anda ingin menjadi pemain tim dan terus menulis seperti ini.
sumber
Python 3.7 dan seterusnya
Dalam Python 3.7, Anda dapat (ab) menggunakan
dataclass
dekorator, tersedia daridataclasses
modul. Dari dokumentasi:Jika kelas Anda besar dan kompleks, mungkin tidak pantas menggunakan a
dataclass
. Saya menulis ini pada hari rilis Python 3.7.0, jadi pola penggunaannya belum mapan.sumber