Apa perbedaan antara:
class Child(SomeBaseClass):
def __init__(self):
super(Child, self).__init__()
dan:
class Child(SomeBaseClass):
def __init__(self):
SomeBaseClass.__init__(self)
Saya telah melihat super
cukup banyak digunakan di kelas dengan hanya satu warisan. Saya bisa melihat mengapa Anda menggunakannya dalam banyak warisan tetapi tidak jelas apa keuntungan menggunakannya dalam situasi seperti ini.
python
oop
inheritance
super
pengguna25785
sumber
sumber
Apa bedanya?
sarana untuk panggilan
SomeBaseClass
's__init__
. sementaraberarti memanggil batasan
__init__
dari kelas induk yang mengikutiChild
dalam Metode Resolution Order (MRO) instance.Jika turunannya adalah subkelas Anak, mungkin ada orangtua yang berbeda yang datang berikutnya di MRO.
Dijelaskan secara sederhana
Saat Anda menulis kelas, Anda ingin kelas lain dapat menggunakannya.
super()
memudahkan kelas lain untuk menggunakan kelas yang Anda tulis.Seperti kata Bob Martin, arsitektur yang baik memungkinkan Anda untuk menunda pengambilan keputusan selama mungkin.
super()
dapat mengaktifkan arsitektur semacam itu.Ketika kelas lain membuat subclass dari kelas yang Anda tulis, itu juga bisa mewarisi dari kelas lain. Dan kelas-kelas itu dapat memiliki
__init__
yang datang setelah ini__init__
berdasarkan urutan kelas-kelas untuk resolusi metode.Tanpa
super
Anda mungkin akan membuat kode-keras induk dari kelas yang Anda tulis (seperti contohnya). Ini berarti bahwa Anda tidak akan memanggil yang berikutnya__init__
di MRO, dan karenanya Anda tidak akan dapat menggunakan kembali kode di dalamnya.Jika Anda menulis kode sendiri untuk penggunaan pribadi, Anda mungkin tidak peduli dengan perbedaan ini. Tetapi jika Anda ingin orang lain menggunakan kode Anda, menggunakan
super
adalah satu hal yang memungkinkan fleksibilitas yang lebih besar bagi pengguna kode.Python 2 lawan 3
Ini berfungsi di Python 2 dan 3:
Ini hanya berfungsi di Python 3:
Ia bekerja tanpa argumen dengan bergerak ke atas dalam stack frame dan mendapatkan argumen pertama ke metode (biasanya
self
untuk metode instance ataucls
untuk metode kelas - tetapi bisa berupa nama lain) dan menemukan kelas (misalnyaChild
) dalam variabel bebas ( itu dilihat dengan nama__class__
sebagai variabel penutupan bebas dalam metode ini).Saya lebih suka menunjukkan cara penggunaan lintas-kompatibel
super
, tetapi jika Anda hanya menggunakan Python 3, Anda bisa menyebutnya tanpa argumen.Tidak Langsung dengan Kompatibilitas Maju
Apa yang kamu berikan? Untuk pewarisan tunggal, contoh-contoh dari pertanyaan praktis identik dari sudut pandang analisis statis. Namun, menggunakan
super
memberi Anda lapisan tipuan dengan kompatibilitas ke depan.Kompatibilitas ke depan sangat penting bagi pengembang berpengalaman. Anda ingin kode Anda tetap bekerja dengan perubahan minimal saat Anda mengubahnya. Ketika Anda melihat riwayat revisi Anda, Anda ingin melihat dengan tepat apa yang berubah kapan.
Anda dapat memulai dengan satu warisan, tetapi jika Anda memutuskan untuk menambahkan kelas dasar lain, Anda hanya perlu mengubah baris dengan basis - jika basis mengubah dalam kelas yang Anda warisi (katakanlah mixin ditambahkan) Anda akan berubah tidak ada di kelas ini. Khususnya di Python 2, mendapatkan argumen
super
dan argumen metode yang benar bisa sulit. Jika Anda tahu Anda menggunakansuper
dengan benar dengan satu warisan, itu membuat debugging lebih sulit untuk maju.Injeksi Ketergantungan
Orang lain dapat menggunakan kode Anda dan menyuntikkan orang tua ke dalam resolusi metode:
Katakanlah Anda menambahkan kelas lain ke objek Anda, dan ingin menyuntikkan kelas antara Foo dan Bar (untuk pengujian atau alasan lain):
Menggunakan un-super child gagal menyuntikkan dependensi karena anak yang Anda gunakan telah meng-hard-code metode yang akan dipanggil setelah sendiri:
Namun, kelas dengan anak yang menggunakan
super
dapat menyuntikkan ketergantungan dengan benar:Mengatasi komentar
Python linierisasi pohon pewarisan yang rumit melalui algoritma linierisasi C3 untuk membuat Method Resolution Order (MRO).
Kami ingin metode dilihat dalam urutan itu .
Untuk metode yang didefinisikan dalam orangtua untuk menemukan yang berikutnya dalam urutan
super
itu, itu harusThe
UnsuperChild
tidak tidak memiliki akses keInjectMe
. Ini adalahUnsuperInjector
yang memiliki akses keInjectMe
- namun tidak dapat memanggil metode kelas itu dari metode yang diwarisi darinyaUnsuperChild
.Kedua kelas Anak bermaksud untuk memanggil metode dengan nama yang sama yang datang berikutnya di MRO, yang mungkin kelas lain yang tidak disadari ketika itu dibuat.
Yang tanpa
super
kode-keras metode induknya - dengan demikian telah membatasi perilaku metodenya, dan subkelas tidak dapat menyuntikkan fungsionalitas dalam rantai panggilan.Satu dengan
super
memiliki fleksibilitas yang lebih besar. Rantai panggilan untuk metode dapat disadap dan fungsi disuntikkan.Anda mungkin tidak memerlukan fungsionalitas itu, tetapi subkelas dari kode Anda mungkin.
Kesimpulan
Selalu gunakan
super
untuk mereferensikan kelas induk alih-alih mengkodekannya.Apa yang Anda maksudkan adalah untuk referensi kelas induk yang berikutnya, tidak secara khusus yang Anda lihat berasal dari anak.
Tidak menggunakan
super
dapat memberikan batasan yang tidak perlu pada pengguna kode Anda.sumber
list
antarmuka, katakandoublylinkedlist
maka aplikasi lancar mengambilnya. Saya dapat membuat contoh saya lebih dapat dikonfigurasi dengan memperkenalkanconfig.txt
dan menghubungkan implementasi pada waktu buka. Apakah ini contoh yang tepat? Jika ya, Bagaimana saya menghubungkan kode Anda? Lihat adv pertama DI di wiki. Di mana implementasi baru dapat dikonfigurasi? dalam kode AndaInjectMe
kelas. Komentar bukan untuk diskusi, jadi saya sarankan Anda mendiskusikan hal ini lebih lanjut dengan orang lain dalam obrolan atau mengajukan pertanyaan baru di situs utama.__init__
fungsi. terutama jika tanda tangan__init__
bervariasi antar kelas dalam hierarki. Saya telah menambahkan jawaban yang berfokus pada aspek iniSaya telah bermain sedikit dengan
super()
, dan telah mengakui bahwa kita dapat mengubah urutan panggilan.Sebagai contoh, kita memiliki struktur hierarki berikutnya:
Dalam hal ini MRO dari D akan menjadi (hanya untuk Python 3):
Mari kita buat kelas tempat
super()
panggilan setelah eksekusi metode.Jadi kita dapat melihat bahwa urutan resolusi sama dengan di MRO. Tetapi ketika kita memanggil
super()
di awal metode:Kami memiliki urutan yang berbeda dengan urutan tuple MRO.
Untuk bacaan tambahan, saya akan merekomendasikan jawaban berikutnya:
sumber
Bukankah semua ini berasumsi bahwa kelas dasar adalah kelas gaya baru?
Tidak akan berfungsi di Python 2.
class A
harus bergaya baru, yaitu:class A(object)
sumber
Saat memanggil
super()
untuk menyelesaikan ke versi orangtua dari metode kelas, metode contoh, atau metode statis, kami ingin meneruskan kelas saat ini yang ruang lingkupnya kita sebagai argumen pertama, untuk menunjukkan ruang lingkup orangtua mana yang ingin kita selesaikan, dan sebagai argumen kedua objek yang menarik untuk menunjukkan ke objek mana kita mencoba menerapkan cakupan itu.Pertimbangkan hirarki kelas
A
,B
danC
di mana masing-masing kelas adalah induk dari satu berikut, dana
,b
, danc
contoh masing-masing.Menggunakan
super
dengan metode statismisalnya menggunakan
super()
dari dalam__new__()
metodePenjelasan:
1 - meskipun biasanya untuk
__new__()
mengambil sebagai param pertama referensi ke kelas panggilan, itu tidak diimplementasikan dalam Python sebagai metode classmet, tetapi metode statis. Artinya, referensi ke kelas harus diberikan secara eksplisit sebagai argumen pertama ketika memanggil__new__()
langsung:2 - ketika memanggil
super()
untuk sampai ke kelas induk kita melewati kelas anakA
sebagai argumen pertama, kemudian kita melewati referensi ke objek yang menarik, dalam hal ini referensi kelas yang disahkan ketikaA.__new__(cls)
dipanggil. Dalam sebagian besar kasus, ini juga merupakan rujukan ke kelas anak. Dalam beberapa situasi mungkin tidak, misalnya dalam kasus warisan beberapa generasi.3 - karena sebagai aturan umum
__new__()
adalah metode statis,super(A, cls).__new__
juga akan mengembalikan metode statis dan perlu diberikan semua argumen secara eksplisit, termasuk referensi ke objek insterest, dalam kasus inicls
.4 - melakukan hal yang sama tanpa
super
Menggunakan
super
dengan metode instanmisalnya menggunakan
super()
dari dalam__init__()
Penjelasan:
1-
__init__
adalah metode instance, yang berarti bahwa argumen pertama sebagai referensi untuk sebuah instance. Ketika dipanggil langsung dari instance, referensi dilewatkan secara implisit, yaitu Anda tidak perlu menentukannya:2 - saat memanggil di
super()
dalam__init__()
kita melewati kelas anak sebagai argumen pertama dan objek yang menarik sebagai argumen kedua, yang secara umum adalah referensi ke turunan dari kelas anak.3- Panggilan
super(A, self)
mengembalikan proxy yang akan menyelesaikan ruang lingkup dan menerapkannyaself
seolah-olah sekarang menjadi instance dari kelas induk. Sebut saja proksi itus
. Karena__init__()
merupakan metode instance, panggilans.__init__(...)
secara implisit akan memberikan referensiself
sebagai argumen pertama ke argumen orang tua__init__()
.4- untuk melakukan hal yang sama tanpa
super
kita perlu memberikan referensi ke instance secara eksplisit ke versi induknya__init__()
.Menggunakan
super
dengan metode kelasPenjelasan:
1- Metodemetode dapat dipanggil dari kelas secara langsung dan mengambil sebagai parameter pertama referensi ke kelas.
2 - saat memanggil
super()
metode class untuk menyelesaikan ke versi induknya, kami ingin meneruskan kelas anak saat ini sebagai argumen pertama untuk menunjukkan cakupan orangtua mana yang kami coba selesaikan, dan objek yang menarik sebagai argumen kedua untuk menunjukkan objek yang ingin kita terapkan lingkup itu, yang secara umum adalah referensi ke kelas anak itu sendiri atau salah satu dari subkelasnya.3- Panggilan
super(B, cls)
memutuskan untuk lingkupA
dan menerapkannyacls
. Karenaalternate_constructor()
merupakan metode kelas panggilansuper(B, cls).alternate_constructor(...)
secara implisit akan memberikan referensicls
sebagai argumen pertama keA
versialternate_constructor()
4- untuk melakukan hal yang sama tanpa menggunakan
super()
Anda harus mendapatkan referensi ke versi tidak terikatA.alternate_constructor()
(yaitu versi eksplisit fungsi). Melakukan hal ini tidak akan berhasil:Di atas tidak akan berfungsi karena
A.alternate_constructor()
metode mengambil referensi implisitA
sebagai argumen pertama. Yangcls
disahkan di sini akan menjadi argumen kedua.sumber
Banyak jawaban bagus, tetapi untuk pelajar visual: Pertama mari kita jelajahi dengan argumen super, dan kemudian tanpa.
Bayangkan ada contoh yang
jack
dibuat dari kelasJack
, yang memiliki rantai pewarisan seperti yang ditunjukkan dengan warna hijau di gambar. Panggilan:super(Jack, jack).method(...)
akan menggunakan MRO (Metode Resolusi Resolusi) dari
jack
(pohon warisannya dalam urutan tertentu), dan akan mulai mencari dariJack
. Mengapa seseorang dapat memberikan kelas induk? Nah jika kita mulai mencari dari instancejack
, itu akan menemukan metode instance, intinya adalah menemukan metode induknya.Jika seseorang tidak memberikan argumen ke super, itu seperti argumen pertama yang diteruskan adalah kelas
self
, dan argumen kedua yang dilewatkan adalahself
. Ini dihitung secara otomatis untuk Anda dalam Python3.Namun katakan kita tidak ingin menggunakan
Jack
metode, alih-alih meneruskanJack
, kita bisa lewatJen
untuk mulai mencari metode dariJen
.Itu mencari satu lapisan pada satu waktu (lebar bukan kedalaman), misalnya jika
Adam
danSue
keduanya memiliki metode yang diperlukan, yang dariSue
akan ditemukan terlebih dahulu.Jika
Cain
danSue
keduanya memiliki metode yang diperlukan,Cain
metode akan dipanggil terlebih dahulu. Ini terkait dalam kode untuk:MRO dari kiri ke kanan.
sumber
beberapa jawaban yang bagus di sini, tetapi mereka tidak membahas bagaimana menggunakannya
super()
dalam kasus di mana kelas yang berbeda dalam hierarki memiliki tanda tangan yang berbeda ... terutama dalam kasus__init__
untuk menjawab bagian itu dan untuk dapat menggunakan secara efektif
super()
saya sarankan membaca jawaban saya super () dan mengubah tanda tangan metode kooperatif .inilah solusi untuk skenario ini:
contoh penggunaan:
keluaran:
sumber
Ini cukup mudah dimengerti.
Oke, apa yang terjadi sekarang jika Anda menggunakan
super(Child,self)
?Ketika turunan Child dibuat, MRO (Method Resolution Order) -nya berada dalam urutan (Child, SomeBaseClass, objek) berdasarkan pewarisan. (anggap SomeBaseClass tidak memiliki orang tua lain kecuali objek default)
Dengan melewatkan
Child, self
,super
mencari di MROself
instance, dan mengembalikan objek proxy di sebelah Child, dalam hal ini SomeBaseClass, objek ini kemudian memanggil__init__
metode SomeBaseClass. Dengan kata lain, jika itusuper(SomeBaseClass,self)
, objek proxy yangsuper
mengembalikan akanobject
Untuk multi inheritance, MRO dapat berisi banyak kelas, jadi pada dasarnya
super
Anda dapat memutuskan di mana Anda ingin mulai mencari di MRO.sumber
Pertimbangkan kode berikut:
Jika mengubah konstruktor
Y
menjadiX.__init__
, Anda akan mendapatkan:Tetapi menggunakan
super(Y, self).__init__()
, Anda akan mendapatkan:Dan
P
atauQ
bahkan mungkin terlibat dari file lain yang Anda tidak tahu kapan Anda menulisX
danY
. Jadi, pada dasarnya, Anda tidak akan tahu apa yangsuper(Child, self)
akan referensi ketika Anda menulisclass Y(X)
, bahkan tanda tangan Y sesederhana ituY(X)
. Itu sebabnya super bisa menjadi pilihan yang lebih baik.sumber