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
dan C
di mana masing-masing kelas adalah induk dari satu berikut, dan a
, b
, dan c
contoh masing-masing.
super(B, b)
# resolves to the scope of B's parent i.e. A
# and applies that scope to b, as if b was an instance of A
super(C, c)
# resolves to the scope of C's parent i.e. B
# and applies that scope to c
super(B, c)
# resolves to the scope of B's parent i.e. A
# and applies that scope to c
Menggunakan super
dengan metode statis
misalnya menggunakan super()
dari dalam __new__()
metode
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return super(A, cls).__new__(cls, *a, **kw)
Penjelasan:
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:
# if you defined this
class A(object):
def __new__(cls):
pass
# calling this would raise a TypeError due to the missing argument
A.__new__()
# whereas this would be fine
A.__new__(A)
2 - ketika memanggil super()
untuk sampai ke kelas induk kita melewati kelas anak A
sebagai argumen pertama, kemudian kita melewati referensi ke objek yang menarik, dalam hal ini referensi kelas yang disahkan ketika A.__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.
super(A, cls)
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 ini cls
.
super(A, cls).__new__(cls, *a, **kw)
4 - melakukan hal yang sama tanpa super
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return object.__new__(cls, *a, **kw)
Menggunakan super
dengan metode instan
misalnya menggunakan super()
dari dalam__init__()
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
super(A, self).__init__(*a, **kw)
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:
# you try calling `__init__()` from the class without specifying an instance
# and a TypeError is raised due to the expected but missing reference
A.__init__() # TypeError ...
# you create an instance
a = A()
# you call `__init__()` from that instance and it works
a.__init__()
# you can also call `__init__()` with the class and explicitly pass the instance
A.__init__(a)
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.
super(A, self)
3- Panggilan super(A, self)
mengembalikan proxy yang akan menyelesaikan ruang lingkup dan menerapkannya self
seolah-olah sekarang menjadi instance dari kelas induk. Sebut saja proksi itu s
. Karena __init__()
merupakan metode instance, panggilan s.__init__(...)
secara implisit akan memberikan referensi self
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__()
.
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
object.__init__(self, *a, **kw)
Menggunakan super
dengan metode kelas
class A(object):
@classmethod
def alternate_constructor(cls, *a, **kw):
print "A.alternate_constructor called"
return cls(*a, **kw)
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return super(B, cls).alternate_constructor(*a, **kw)
Penjelasan:
1- Metodemetode dapat dipanggil dari kelas secara langsung dan mengambil sebagai parameter pertama referensi ke kelas.
# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()
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.
super(B, cls_or_subcls)
3- Panggilan super(B, cls)
memutuskan untuk lingkup A
dan menerapkannya cls
. Karena alternate_constructor()
merupakan metode kelas panggilan super(B, cls).alternate_constructor(...)
secara implisit akan memberikan referensi cls
sebagai argumen pertama ke A
versialternate_constructor()
super(B, cls).alternate_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:
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return A.alternate_constructor(cls, *a, **kw)
Di atas tidak akan berfungsi karena A.alternate_constructor()
metode mengambil referensi implisit A
sebagai argumen pertama. Yang cls
disahkan di sini akan menjadi argumen kedua.
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
# first we get a reference to the unbound
# `A.alternate_constructor` function
unbound_func = A.alternate_constructor.im_func
# now we call it and pass our own `cls` as its first argument
return unbound_func(cls, *a, **kw)