Panggil metode kelas induk dari kelas anak?

608

Saat membuat hierarki objek sederhana dalam Python, saya ingin dapat memanggil metode dari kelas induk dari kelas turunan. Di Perl dan Java, ada kata kunci untuk ini ( super). Di Perl, saya mungkin melakukan ini:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

sub frotz {
   my $str = SUPER::frotz();
   return uc($str);
}

Dalam Python, tampaknya saya harus memberi nama kelas induk secara eksplisit dari anak. Pada contoh di atas, saya harus melakukan sesuatu seperti Foo::frotz().

Ini sepertinya tidak benar karena perilaku ini menyulitkan untuk membuat hierarki yang mendalam. Jika anak-anak perlu tahu kelas apa yang mendefinisikan metode yang diwariskan, maka semua jenis rasa sakit informasi dibuat.

Apakah ini keterbatasan sebenarnya dalam python, celah dalam pemahaman saya atau keduanya?

John
sumber
3
Saya pikir penamaan kelas induk bukan ide yang buruk. Ini dapat membantu ketika kelas anak mewarisi dari lebih dari satu orangtua, karena Anda secara eksplisit menyebutkan kelas induknya.
7
Sementara opsi untuk memberi nama kelas bukanlah ide yang buruk, dipaksa untuk melakukannya tentu saja.
johndodo
Waspadai perubahan penanganan super antara Python 2 dan Python 3 https://www.python.org/dev/peps/pep-3135/ . Memberi nama kelas tidak lagi diperlukan (meskipun mungkin masih merupakan ide dewa, setidaknya kadang-kadang).
jwpfox

Jawaban:

737

Ya, tetapi hanya dengan kelas gaya baru . Gunakan super()fungsinya:

class Foo(Bar):
    def baz(self, arg):
        return super().baz(arg)

Untuk python <3, gunakan:

class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)
Adam Rosenfield
sumber
53
Tidak bisakah kamu juga melakukan "return Bar.baz (self, arg)"? Jika demikian, mana yang lebih baik?
15
Ya, Anda bisa, tetapi OP bertanya bagaimana melakukannya tanpa secara eksplisit memberi nama superclass di situs panggilan (Bar, dalam hal ini).
Adam Rosenfield
7
super () aneh dengan banyak pewarisan. Itu panggilan ke kelas "berikutnya". Itu mungkin kelas induk, atau mungkin beberapa kelas yang sama sekali tidak terkait yang muncul di tempat lain dalam hierarki.
Steve Jessop
6
Saya menggunakan Python 2.x, dan saya mendapatkan "Kesalahan: harus mengetik, bukan classobj" ketika saya melakukan ini
Chris F
28
Sintaksnya super(Foo, self)untuk Python 2.x benar? Dalam Python 3.x, super()lebih disukai benar?
Trevor Boyd Smith
144

Python juga memiliki super juga:

super(type[, object-or-type])

Mengembalikan objek proxy yang mendelegasikan panggilan metode ke kelas tipe induk atau saudara kandung. Ini berguna untuk mengakses metode yang diwariskan yang telah ditimpa dalam kelas. Urutan pencarian sama dengan yang digunakan oleh getattr () kecuali bahwa tipe itu sendiri dilewati.

Contoh:

class A(object):     # deriving from 'object' declares A as a 'new-style-class'
    def foo(self):
        print "foo"

class B(A):
    def foo(self):
        super(B, self).foo()   # calls 'A.foo()'

myB = B()
myB.foo()
Jay
sumber
7
Contoh yang lebih baik daripada Adam karena Anda menunjukkan menggunakan kelas gaya baru dengan kelas objek dasar. Baru saja kehilangan tautan ke kelas gaya baru.
Samuel
83
ImmediateParentClass.frotz(self)

akan baik-baik saja, apakah kelas induk langsung didefinisikan frotzsendiri atau diwarisi. superhanya diperlukan untuk dukungan yang tepat dari multiple inheritance (dan kemudian hanya berfungsi jika setiap kelas menggunakannya dengan benar). Secara umum, AnyClass.whateverakan mencari whateverdi AnyClassleluhur 's jika AnyClasstidak mendefinisikan / menimpa itu, dan ini berlaku untuk 'kelas anak memanggil metode orangtua' seperti untuk terjadinya lainnya!

Alex Martelli
sumber
Ini mengamanatkan bahwa ImmediateParentClass juga hadir dalam ruang lingkup untuk pernyataan ini dieksekusi. Hanya memiliki objek yang diimpor dari modul tidak akan membantu.
Tushar Vazirani
bagaimana jika metode kelasnya?
Shiplu Mokaddim
@TusharVazirani jika kelas induk adalah langsung parent, itu berada dalam lingkup seluruh kelas, bukan?
Yaroslav Nikitenko
1
@YaroslavNikitenko Saya berbicara tentang mengimpor sebuah instance, bukan kelas.
Tushar Vazirani
1
@TusharVazirani sekarang saya mengerti, terima kasih. Saya sedang berpikir untuk memanggil dari metode kelas saat ini (seperti yang dinyatakan oleh OP).
Yaroslav Nikitenko
75

Python 3 memiliki sintaks yang berbeda dan lebih sederhana untuk memanggil metode induk.

Jika Fookelas mewarisi dari Bar, maka dari Bar.__init__dapat dipanggil Foomelalui super().__init__():

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)
Arun Ghosh
sumber
5
Senang mendengar python 3 memiliki solusi yang lebih baik. Pertanyaannya berasal dari python 2.X. Terima kasih untuk sarannya.
jjohn
46

Banyak jawaban telah menjelaskan cara memanggil metode dari orang tua yang telah ditimpa pada anak.

Namun

"Bagaimana kamu memanggil metode kelas induk dari kelas anak?"

bisa juga berarti:

"Bagaimana Anda memanggil metode yang diwariskan?"

Anda dapat memanggil metode yang diwarisi dari kelas induk sama seperti jika mereka adalah metode kelas anak, asalkan mereka belum ditimpa.

misalnya dalam python 3:

class A():
  def bar(self, string):
    print("Hi, I'm bar, inherited from A"+string)

class B(A):
  def baz(self):
    self.bar(" - called by baz in B")

B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"

ya, ini mungkin cukup jelas, tetapi saya merasa bahwa tanpa menunjukkan ini orang dapat meninggalkan utas ini dengan kesan Anda harus melompat melalui lingkaran konyol hanya untuk mengakses metode yang diwariskan dalam python. Terutama karena pertanyaan ini sangat dicari dalam "cara mengakses metode kelas induk dengan Python", dan OP ditulis dari sudut pandang seseorang yang baru mengenal python.

Saya menemukan: https://docs.python.org/3/tutorial/classes.html#inheritance berguna dalam memahami bagaimana Anda mengakses metode yang diwariskan.

Ben
sumber
@ gizzmole dalam situasi apa ini tidak berfungsi? Saya senang menambahkan peringatan atau peringatan apa pun yang relevan, tetapi saya tidak tahu bagaimana tautan yang Anda poskan relevan dengan jawaban ini.
Ben
@ Ben Maaf, saya tidak cukup membaca jawaban Anda. Jawaban ini tidak menjawab pertanyaan tentang cara kelebihan fungsi, tetapi menjawab pertanyaan yang berbeda. Saya menghapus komentar awal saya.
gizzmole
@ gizzmole ah, jangan khawatir. Saya menyadari bahwa jawaban ini tidak berlaku untuk fungsi overloading, namun pertanyaannya tidak secara eksplisit menyebutkan overloading (meskipun contoh perl yang diberikan memang menunjukkan kasus overloading). Sebagian besar jawaban lain mencakup kelebihan beban - jawaban ini ada di sini untuk orang-orang yang tidak membutuhkannya.
Ben
@ Lalu bagaimana jika saya ingin memanggil B (). Baz () dari kelas lain bernama 'C' menggunakan vars yang didefinisikan dalam C ?. Saya mencoba melakukan B (). Baz () di kelas C, di mana self.string adalah val lain. Itu tidak memberi saya, ketika saya dieksekusi
joey
@ joey, saya tidak yakin apa yang Anda coba lakukan, atau apakah itu dalam lingkup pertanyaan ini. String adalah variabel lokal - pengaturan self.stringtidak akan melakukan apa pun. Namun di kelas C Anda masih bisa meneleponB().bar(string)
Ben
27

Berikut adalah contoh penggunaan super () :

#New-style classes inherit from object, or from another new-style class
class Dog(object):

    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self):
        self.moves.append('walk')
        self.moves.append('run')

    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super(Superdog, self).moves_setup()
        self.moves.append('fly')

dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly']. 
#As you can see our Superdog has all moves defined in the base Dog class
yesnik
sumber
Bukankah ini contoh yang buruk? Saya percaya itu tidak benar-benar aman untuk menggunakan Super kecuali seluruh hierarki Anda adalah kelas "gaya baru" dan memanggil Super (). Init ()
Jaykul
14

Ada super () di Python juga. Ini agak miring, karena kelas gaya lama dan baru Python, tetapi cukup umum digunakan misalnya dalam konstruktor:

class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5
lawrence
sumber
10

Saya akan merekomendasikan menggunakan CLASS.__bases__ sesuatu seperti ini

class A:
   def __init__(self):
        print "I am Class %s"%self.__class__.__name__
        for parentClass in self.__class__.__bases__:
              print "   I am inherited from:",parentClass.__name__
              #parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()
Joran Beasley
sumber
1
Ingatlah bahwa, seperti yang Anda tahu dari volume referensi ke super di sini, bahwa orang benar-benar enggan menggunakan pangkalan kecuali Anda melakukan sesuatu yang sangat mendalam. Jika Anda tidak suka super , lihat mro . Mengambil entri pertama dalam mro lebih aman daripada melacak entri mana dalam basis untuk digunakan. Warisan berganda di Python memindai hal-hal tertentu ke belakang dan yang lain ke depan, sehingga membiarkan bahasa melepaskan prosesnya adalah yang paling aman.
Jon Jay Obermark
5

Ada super () di python juga.

Contoh untuk bagaimana metode kelas super dipanggil dari metode kelas bawah

class Dog(object):
    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self,x):
        self.moves.append('walk')
        self.moves.append('run')
        self.moves.append(x)
    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super().moves_setup("hello world")
        self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves()) 

Contoh ini mirip dengan yang dijelaskan di atas. Namun ada satu perbedaan yang super tidak memiliki argumen yang dilewatinya. Kode di atas ini dapat dieksekusi dalam versi python 3.4.

kkk
sumber
3

Dalam contoh ini cafec_paramadalah kelas dasar (kelas induk) dan abcmerupakan kelas anak. abcmemanggil AWCmetode di kelas dasar.

class cafec_param:

    def __init__(self,precip,pe,awc,nmonths):

        self.precip = precip
        self.pe = pe
        self.awc = awc
        self.nmonths = nmonths

    def AWC(self):

        if self.awc<254:
            Ss = self.awc
            Su = 0
            self.Ss=Ss
        else:
            Ss = 254; Su = self.awc-254
            self.Ss=Ss + Su   
        AWC = Ss + Su
        return self.Ss


    def test(self):
        return self.Ss
        #return self.Ss*4

class abc(cafec_param):
    def rr(self):
        return self.AWC()


ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())

Keluaran

56

56

56
Khan
sumber
2

Dalam Python 2, saya tidak memiliki banyak keberuntungan dengan super (). Saya menggunakan jawaban dari jimifiki pada utas SO ini bagaimana merujuk ke metode induk dengan python?. Kemudian, saya menambahkan sedikit twist saya sendiri untuk itu, yang saya pikir merupakan peningkatan dalam kegunaan (Terutama jika Anda memiliki nama kelas yang panjang).

Tentukan kelas dasar dalam satu modul:

 # myA.py

class A():     
    def foo( self ):
        print "foo"

Kemudian impor kelas ke modul lain as parent:

# myB.py

from myA import A as parent

class B( parent ):
    def foo( self ):
        parent.foo( self )   # calls 'A.foo()'
Terima kasih
sumber
2
Anda harus menggunakan class A(object): alih-alih class A(): Then super () akan bekerja
blndev
Saya tidak yakin saya mengikuti. Apakah maksud Anda dalam definisi kelas? Jelas, Anda harus menunjukkan bahwa suatu kelas memiliki orang tua, entah bagaimana, untuk berpikir Anda bisa merujuk ke orang tua! Karena, saya memposting ini 9 bulan yang lalu, saya agak kabur dan detail, tapi saya pikir saya maksudkan contoh-contoh dari Arun Ghosh, lawrence, kkk, dll. Tidak berlaku di Py 2.x. Alih-alih, inilah metode yang berfungsi dan cara mudah untuk merujuk ke orang tua sehingga sedikit lebih jelas apa yang Anda lakukan. (seperti menggunakan super)
BuvinJ
0
class department:
    campus_name="attock"
    def printer(self):
        print(self.campus_name)

class CS_dept(department):
    def overr_CS(self):
        department.printer(self)
        print("i am child class1")

c=CS_dept()
c.overr_CS()
maryam mehboob
sumber
-3
class a(object):
    def my_hello(self):
        print "hello ravi"

class b(a):
    def my_hello(self):
    super(b,self).my_hello()
    print "hi"

obj = b()
obj.my_hello()
RAVIKUMAR RACHA
sumber
2
Selamat datang di stackoverflow. Pertanyaan ini telah dijawab secara terperinci hampir sepuluh tahun yang lalu sekarang, jawabannya diterima dan sebagian besar telah di-upgrade, dan jawaban Anda tidak menambahkan sesuatu yang baru. Anda mungkin ingin mencoba dan menjawab pertanyaan yang lebih baru (dan lebih baik tidak dijawab) sebagai gantinya. Sebagai catatan, ada tombol di editor untuk menerapkan pemformatan kode yang tepat.
bruno desthuilliers
-24

Ini adalah metode yang lebih abstrak:

super(self.__class__,self).baz(arg)
pengguna806071
sumber
15
self .__ class__ tidak berfungsi dengan benar karena super selalu menjadi instance dan kelasnya selalu merupakan instance instance. Ini berarti jika Anda menggunakan super (self .__ class__ .. dalam suatu kelas dan dari sana kelas itu diturunkan, itu tidak akan berfungsi lagi.
xitrium
16
Hanya untuk menekankan, JANGAN GUNAKAN KODE INI. Ini mengalahkan seluruh tujuan super (), yaitu untuk melewati MRO dengan benar.
Eevee
1
stackoverflow.com/a/19257335/419348 mengatakan mengapa tidak menelepon super(self.__class__, self).baz(arg).
AechoLiu