Dalam Python 3.x, super()
dapat dipanggil tanpa argumen:
class A(object):
def x(self):
print("Hey now")
class B(A):
def x(self):
super().x()
>>> B().x()
Hey now
Untuk membuat ini bekerja, beberapa sihir waktu kompilasi dilakukan, salah satu konsekuensinya adalah bahwa kode berikut (yang rebind super
ke super_
) gagal:
super_ = super
class A(object):
def x(self):
print("No flipping")
class B(A):
def x(self):
super_().x()
>>> B().x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found
Mengapa super()
tidak dapat menyelesaikan superclass saat runtime tanpa bantuan dari kompiler? Apakah ada situasi praktis di mana perilaku ini, atau alasan yang mendasarinya, dapat menggigit programmer yang tidak waspada?
... dan, sebagai pertanyaan sampingan: apakah ada contoh lain dalam Python fungsi, metode, dll. yang dapat dipecah dengan memutarkannya ke nama yang berbeda?
python
python-3.x
super
Zero Piraeus
sumber
sumber
Jawaban:
super()
Perilaku sulap baru ditambahkan untuk menghindari melanggar prinsip KERING (Jangan Ulangi Diri Sendiri), lihat PEP 3135 . Harus secara eksplisit memberi nama kelas dengan merujuknya sebagai global juga rentan terhadap masalah rebinding yang Anda temukan dengansuper()
dirinya sendiri:Hal yang sama berlaku untuk menggunakan dekorator kelas di mana dekorator mengembalikan objek baru, yang mengubah nama kelas:
super()
__class__
Sel ajaib menghindari masalah ini dengan baik dengan memberi Anda akses ke objek kelas asli.PEP diluncurkan oleh Guido, yang awalnya membayangkan
super
menjadi kata kunci , dan gagasan menggunakan sel untuk mencari kelas saat ini juga miliknya . Tentu saja, gagasan untuk menjadikannya kata kunci adalah bagian dari konsep pertama PEP .Namun, sebenarnya Guido sendiri yang kemudian menjauh dari gagasan kata kunci sebagai 'terlalu ajaib' , malah mengusulkan penerapan saat ini. Dia mengantisipasi bahwa menggunakan nama yang berbeda untuk
super()
bisa menjadi masalah :Jadi, pada akhirnya, Guido sendiri yang menyatakan bahwa menggunakan
super
kata kunci tidak terasa benar, dan bahwa menyediakan__class__
sel ajaib adalah kompromi yang dapat diterima.Saya setuju bahwa keajaiban, perilaku implisit implementasi agak mengejutkan, tetapi
super()
merupakan salah satu fungsi yang paling salah diterapkan dalam bahasa. Lihat saja semua kesalahan penggunaansuper(type(self), self)
atausuper(self.__class__, self)
doa yang ditemukan di Internet; jika ada kode yang dipanggil dari kelas turunan, Anda akan berakhir dengan pengecualian rekursi tak terbatas . Di sangat paling tidak disederhanakansuper()
panggilan, tanpa argumen, menghindari itu masalah.Adapun yang diganti namanya
super_
; referensi saja__class__
dalam metode Anda juga dan itu akan bekerja lagi. Sel dibuat jika Anda merujuk salah satusuper
atau__class__
nama - nama dalam metode Anda:sumber
def super(of_class=magic __class__)
jenis sepertiself.super(); def super(self): return self.__class__
?super()
tanpa argumen berfungsi; sebagian besar berkaitan dengan mengapa itu ada.super()
, dalam metode kelas, sama dengansuper(ReferenceToClassMethodIsBeingDefinedIn, self)
, di manaReferenceToClassMethodIsBeingDefinedIn
ditentukan pada waktu kompilasi, dilampirkan pada metode sebagai penutup bernama__class__
, dansuper()
akan mencari keduanya dari bingkai panggilan saat runtime. Tapi Anda sebenarnya tidak perlu tahu semua ini.super()
tidak ada yang dekat dengan fungsi yang dipakai secara otomatis , no.__class__
dalam metode Anda . Anda menggunakan namasuper
dalam fungsi Anda. Kompilator melihat itu dan menambahkan__class__
penutup.type(self)
memberikan tipe saat ini , yang tidak sama dengan tipe metode yang didefinisikan. Jadi kelasFoo
dengan metodebaz
kebutuhansuper(Foo, self).baz()
, karena bisa subclassed sebagaiclass Ham(Foo):
, di mana titiktype(self)
adalahHam
dansuper(type(self), self).baz()
akan memberikan loop tak terbatas. Lihat posting yang saya tautkan ke dalam jawaban saya: Saat memanggil super () di kelas turunan, dapatkah saya lulus sendiri .__ class__?