Bir üst sınıfın yöntemini alt sınıftan mı çağırıyorsunuz?


607

Python'da basit bir nesne hiyerarşisi oluştururken, türetilmiş bir sınıftan üst sınıf yöntemlerini çağırabilmek istiyorum. Perl ve Java'da bunun için bir anahtar kelime vardır ( super). Perl'de bunu yapabilirim:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

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

Python, alt sınıf açıkça alt sınıf adlandırmak zorunda gibi görünüyor. Yukarıdaki örnekte, böyle bir şey yapmam gerekirdi Foo::frotz().

Bu doğru görünmüyor çünkü bu davranış derin hiyerarşiler oluşturmayı zorlaştırıyor. Çocukların hangi sınıfın kalıtsal bir yöntemi tanımladığını bilmesi gerekiyorsa, her türlü bilgi ağrısı yaratılır.

Bu, python'da gerçek bir sınırlama mı, anlayışımdaki bir boşluk mu yoksa her ikisi de mi?


3
Bence ana sınıfın isimlendirilmesi o kadar da kötü bir fikir değil. Üst sınıfı açıkça adlandırdığınız için, alt sınıf birden fazla üst öğeden miras aldığınızda yardımcı olabilir.

7
Bir sınıfı isimlendirme seçeneği kötü bir fikir olmasa da, bunu yapmak zorunda kalmak kesinlikle zor.
johndodo

Python 2 ve Python 3 arasındaki süper kullanım değişikliklerinin farkında olun https://www.python.org/dev/peps/pep-3135/ . Sınıfı adlandırmak artık gerekli değildir (yine de en azından bazen bir tanrı fikri olabilir).
jwpfox

Yanıtlar:


736

Evet, ama sadece yeni stil sınıflarıyla . super()İşlevi kullanın :

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

<3 python için şunları kullanın:

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

53
"Dönüş Bar.baz (self, arg)" yapamaz mısınız? Eğer öyleyse hangisi daha iyi olurdu?

15
Evet, yapabilirsiniz, ancak OP çağrı sitesinde üst sınıfı açıkça adlandırmadan bunu nasıl yapacağını soruyordu (bu durumda Bar).
Adam Rosenfield

7
super () çok sayıda miras ile garip. "Bir sonraki" sınıfa çağırır. Bu ana sınıf olabilir veya hiyerarşinin başka bir yerinde görünen tamamen ilgisiz bir sınıf olabilir.
Steve Jessop

6
Python 2.x kullanıyorum ve bunu yaptığımda "Hata: türü olmalı, classobj değil" alıyorum
Chris F

28
super(Foo, self)Python 2.x sözdizimi doğru mu? Python 3.x'te super()doğru tercih edilir mi?
Trevor Boyd Smith

144

Python da süper var :

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

Bir üst veya kardeş sınıf sınıfına yöntem çağrılarını devreten bir proxy nesnesi döndürün. Bu, bir sınıfta geçersiz kılınmış kalıtsal yöntemlere erişmek için kullanışlıdır. Arama sırası, türün kendisinin atlanması dışında getattr () tarafından kullanılanla aynıdır.

Misal:

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()

7
Adam'ınkinden daha iyi bir örnek çünkü nesne taban sınıfıyla yeni bir stil sınıfı kullandığınızı gösterdiniz. Sadece yeni stil sınıflarının bağlantısını kaçırıyorum.
Samuel

83
ImmediateParentClass.frotz(self)

ana sınıfın frotzkendisini tanımlaması veya miras alması iyi olur. superyalnızca çoklu kalıtımın doğru şekilde desteklenmesi için gereklidir (ve daha sonra yalnızca her sınıf bunu doğru kullanıyorsa çalışır). Genel olarak, AnyClass.whateverbakmak için gidiyor whateveriçinde AnyClasseğer insan atalarının AnyClass/ tanımlamak bunu geçersiz kılmaz ve bu da başka bir oluşum için olduğu gibi 'ebeveyn yöntemini çağırarak çocuk sınıfına' için de geçerlidir!


Bu, bu ifadenin yürütülmesi için ImmediateParentClass öğesinin de kapsam içinde bulunmasını zorunlu kılar. Nesnenin bir modülden içe aktarılması yardımcı olmaz.
Tushar Vazirani

ya bir sınıf yöntemi ise?
Shiplu Mokaddim

@TusharVazirani eğer ana sınıf hemen bir sınıfsa parent, tüm sınıfın kapsamındadır, değil mi?
Yaroslav Nikitenko

1
@YaroslavNikitenko Ben sınıftan değil, bir örneği ithal etmekten söz ediyorum.
Tushar Vazirani

1
@TusharVazirani şimdi anlıyorum, teşekkür ederim. Mevcut sınıfın yönteminden (OP tarafından belirtildiği gibi) çağrı düşünüyordum.
Yaroslav Nikitenko

75

Python 3 , ana yöntemi çağırmak için farklı ve daha basit bir sözdizimine sahiptir.

Eğer Foosınıfını miras dan Barsonra gelen Bar.__init__çağrılabilir Fooyoluyla super().__init__():

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)

5
Python 3'ün daha iyi bir çözümü olduğunu duymak güzel. Soru python 2.X'den geliyor. Yine de öneri için teşekkürler.
jjohn

46

Birçok cevap, çocukta geçersiz kılınan ebeveynten bir yöntemin nasıl çağrılacağını açıkladı.

ancak

"Bir üst sınıfın yöntemini alt sınıftan nasıl çağırıyorsunuz?"

sadece şu anlama gelebilir:

"Kalıtsal yöntemler nasıl adlandırılır?"

Üst sınıftan miras alınan yöntemleri, tıpkı üzerine yazılmadığı sürece, alt sınıfın yöntemleriymiş gibi çağırabilirsiniz.

örneğin python 3'te:

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"

Evet, bu oldukça açık olabilir, ama bunu işaret etmeden insanların bu ipliği python'da kalıtsal yöntemlere erişmek için saçma çemberlerden atlamak zorunda olduğu izlenimiyle bırakabileceğini hissediyorum. Özellikle bu soru, "Python'da bir ana sınıfın yöntemine nasıl erişileceği" aramalarında yüksek oranda derecelendirilir ve OP, python'a yeni birinin bakış açısından yazılır.

Kalıtımsal yöntemlere nasıl eriştiğinizi anlamada yararlı olduğunu https://docs.python.org/3/tutorial/classes.html#inheritance buldum .


@gizzmole hangi durumda çalışmıyor? Alakalı uyarılar veya uyarılar eklemekten mutluluk duyuyorum, ancak gönderdiğiniz bağlantının bu yanıtla nasıl alakalı olduğunu anlayamadım.
Ben

@Ben Üzgünüm, cevabınızı yeterince dikkatli okumadım. Bu cevap, işlevlerin aşırı yüklenmesi ile ilgili soruya cevap vermez, ancak farklı bir soruyu cevaplar. İlk yorumumu sildim.
gizzmole

@gizzmole ah, endişelenme. Bu cevabın aşırı yükleme fonksiyonlarına uygulanmadığını, ancak sorunun açıkça aşırı yüklemeden bahsetmediğini (verilen perl örneği aşırı yüklenme durumu göstermesine rağmen) fark ediyorum. Diğer cevapların büyük çoğunluğu aşırı yüklemeyi kapsıyor - bu, ihtiyaç duymayanlar için burada.
Ben

@ B'de tanımlanmış vars kullanarak 'C' adlı başka bir sınıftan B (). Baz () öğesini çağırmak istersem ne olur? Self.string'in başka bir val olduğu C sınıfında B (). Baz () yapmayı denedim. Yaptığım zaman bana hiçbir şey vermedi
joey

@joey Ne yapmaya çalıştığınızdan veya bu sorunun kapsamında olup olmadığından emin değilim. Dize yerel bir değişkendir - ayar self.stringhiçbir şey yapmaz. C sınıfında yine de arayabilirsinizB().bar(string)
Ben

27

Super () kullanımına bir örnek :

#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

Bu kötü bir örnek değil mi? Tüm hiyerarşiniz "yeni stil" sınıfları ve doğru şekilde Super () olarak adlandırılmadığı sürece Super'i kullanmanın gerçekten güvenli olmadığına inanıyorum init ()
Jaykul

14

Python'da da bir süper () var. Python'un eski ve yeni stil sınıfları nedeniyle biraz sakat, ancak örneğin inşaatçılarda oldukça yaygın olarak kullanılıyor:

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

10

CLASS.__bases__ Böyle bir şey kullanmanızı tavsiye ederim

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()

1
Eğer yapılan atıflar hacmi söyleyebilirim olarak akılda tutmak, o süper burada, bu millet gerçekten kullanımı isteksiz olan bazlar gerçekten derin bir şey yapıyorsun sürece. Süper sevmiyorsanız , mro'ya bakın . Mro'daki ilk girişi kullanmak , baz istasyonlarında hangi girdinin kullanılacağını izlemekten daha güvenlidir . Python'daki çoklu kalıtım belirli şeyleri geriye doğru ve diğerlerini ileriye doğru tarar, böylece dilin süreci çözmesine izin vermek en güvenlidir.
Jon Jay Obermark


5

Python'da da bir süper () vardır.

Bir alt sınıf yönteminden bir süper sınıf yönteminin nasıl çağrıldığına örnek

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()) 

Bu örnek, yukarıda açıklanan örneğe benzer, ancak süper değişkenin kendisine iletilen herhangi bir argümanı olmayan bir fark vardır. Yukarıdaki kod python 3.4 sürümünde yürütülebilir.


3

Bu örnekte cafec_parambir temel sınıf (üst sınıf) ve abcbir alt sınıftır. temel sınıftaki yöntemi abcçağırır AWC.

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())

Çıktı

56

56

56

2

Python 2'de super () ile pek şansım yoktu. Python bir üst yönteme başvurmak nasıl bu SO iş parçacığında jimifiki gelen cevap kullanılır ?. Sonra, kendi küçük bükümümü ekledim, bu da kullanılabilirlikte bir gelişme olduğunu düşünüyorum (Özellikle uzun sınıf isimleriniz varsa).

Temel sınıfı bir modülde tanımlayın:

 # myA.py

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

Ardından sınıfı başka bir modüle alın as parent:

# myB.py

from myA import A as parent

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

2
O zaman süper () işe yarayacak class A(object): yerine kullanmalısınız class A():
blndev

Takip ettiğimden emin değilim. Sınıfın tanımında ne demek istiyorsun? Açıkçası, bir ebeveyne başvurabileceğinizi düşünmek için bir sınıfın bir ebeveyne sahip olduğunu belirtmelisiniz! Bunu 9 ay önce yayınladığımdan beri, ayrıntılarda biraz bulanıkım, ancak bence Arun Ghosh, lawrence, kkk, vb. Örnekleri Py 2.x'te geçerli değil. Bunun yerine, çalışan bir yöntem ve ebeveyne başvurmanın kolay bir yolu, bu yüzden ne yaptığınızı biraz daha açık. (super kullanmak gibi)
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()

-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()

2
Stackoverflow'a hoş geldiniz. Bu soru neredeyse on yıl önce ayrıntılı olarak cevaplandı, cevap kabul edildi ve büyük ölçüde kaldırıldı ve cevabınız yeni bir şey eklemiyor. Bunun yerine daha yeni (ve tercihen cevaplanmamış) soruları cevaplamayı denemek isteyebilirsiniz. Bir yan not olarak, editörde uygun kod formatını uygulamak için bir düğme vardır.
bruno desthuilliers

-24

Bu daha soyut bir yöntemdir:

super(self.__class__,self).baz(arg)

15
self .__ class__, super ile doğru çalışmaz çünkü self her zaman bir örnektir ve sınıfı her zaman örneğin bir sınıftır. Bu, bir sınıfta süper (self .__ class__ .. kullanırsanız ve bu sınıfın miras alınması durumunda artık çalışmaz.
xitrium

16
Sadece vurgulamak için, BU KODU KULLANMAYIN. MRO'yu doğru bir şekilde hareket ettirmek için super () 'nin tüm amacını yener.
Eevee

1
stackoverflow.com/a/19257335/419348 neden aramamanızı söyledi super(self.__class__, self).baz(arg).
AechoLiu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.