'Süper' Python'da ne yapar?


564

Arasındaki fark nedir:

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

ve:

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

superSadece tek bir mirasa sahip sınıflarda oldukça fazla kullanıldığını gördüm . Neden birden fazla mirasta kullanacağınızı anlayabiliyorum, ancak bu tür bir durumda kullanmanın avantajlarının ne olduğu konusunda net değilim.

Yanıtlar:


309

Tek mirastaki yararları super()minimumdur - çoğunlukla, temel sınıfın adını üst yöntemlerini kullanan her yönteme zorla kodlamanız gerekmez.

Ancak, çoklu kalıtım kullanmak neredeyse imkansızdır super(). Bu, mixins, arayüzler, soyut sınıflar, vb. Gibi yaygın deyimleri içerir. Bu, daha sonra sizinkini genişleten koda uzanır. Birisi daha sonra genişletilmiş bir sınıf Childve bir mixin yazmak isterse, kodu düzgün çalışmaz.


6
"düzgün çalışmaz" demekle bir örnek verebilir misiniz?
Charlie Parker

319

Fark ne?

SomeBaseClass.__init__(self) 

çağrısına vasıta SomeBaseClass's __init__. süre

super(Child, self).__init__()

__init__üst sınıftan Child, örneğin Yöntem Çözüm Sırası'nda (MRO) bir bağlı çağırmak anlamına gelir .

Örnek bir Child alt sınıfıysa, MRO'da gelecek olan farklı bir üst öğe olabilir.

Basitçe açıklanır

Bir sınıf yazdığınızda, başka sınıfların da kullanabilmesini istiyorsunuz. super()diğer sınıfların yazdığınız sınıfı kullanmasını kolaylaştırır.

Bob Martin'in dediği gibi, iyi bir mimari, karar vermeyi mümkün olduğu kadar ertelemenize izin verir.

super() bu tür mimariyi etkinleştirebilir.

Başka bir sınıf yazdığınız sınıfı alt sınıflara ayırdığında, diğer sınıflardan da miras alınabilir. Ve bu sınıflar, yöntem çözümlemesi için sınıfların sırasına göre __init__bundan sonra gelen bir sınıflara sahip olabilir __init__.

Olmadan superbüyük olasılıkla sabit kod sınıfının ebeveyn sen yazıyoruz olur (örnek yaptığı gibi). Bu __init__, MRO'da bir sonrakini çağırmayacağınız ve böylece içindeki kodu yeniden kullanamayacağınız anlamına gelir.

Kişisel kullanım için kendi kodunuzu yazıyorsanız, bu ayrımı önemsemeyebilirsiniz. Ancak başkalarının kodunuzu kullanmasını istiyorsanız, kod superkullanıcıları için daha fazla esneklik sağlayan bir şey kullanmaktır .

Python 2 ve 3

Bu Python 2 ve 3'te çalışır:

super(Child, self).__init__()

Bu yalnızca Python 3'te çalışır:

super().__init__()

Yığın çerçevesinde yukarı hareket ederek ve yönteme ilk argümanı (genellikle selfbir örnek yöntemi veya clsbir sınıf yöntemi için - ancak başka adlar olabilir Child) alarak ve serbest değişkenlerde ( örn. ) Sınıfı bularak argüman olmadan çalışır. o isimde aranır __class__yönteminde bir serbest kapatma değişken) olarak.

Çapraz uyumlu kullanım şeklini göstermeyi tercih ediyorum super, ancak sadece Python 3 kullanıyorsanız, bunu argüman olmadan çağırabilirsiniz.

İleri Uyumluluğa Sahip Dolaylı İndirimler

Size ne veriyor? Tek miras için, sorunun örnekleri statik analiz açısından pratik olarak aynıdır. Ancak, kullanmak supersize ileri uyumluluğa sahip bir dolaylı katman sağlar.

İleri uyumluluk, deneyimli geliştiriciler için çok önemlidir. Kodunuzu değiştirdiğinizde minimum değişikliklerle çalışmaya devam etmesini istiyorsunuz. Düzeltme geçmişinize baktığınızda, neyin ne zaman değiştiğini tam olarak görmek istersiniz.

Tek bir kalıtımla başlayabilirsiniz, ancak başka bir temel sınıf eklemeye karar verirseniz, yalnızca tabanlarla olan satırı değiştirmeniz gerekir - devraldığınız bir sınıftaki bazlar değişirse (bir mixin eklendiğini söyleyin) bu sınıfta hiçbir şey yok. Özellikle Python 2'de, argümanlara superve doğru yöntem argümanlarına doğru bir şekilde ulaşmak zor olabilir. superTek bir miras ile doğru şekilde kullandığınızı biliyorsanız , bu hata ayıklamayı daha az zorlaştırır.

Bağımlılık Enjeksiyonu

Diğer kişiler kodunuzu kullanabilir ve ebeveynlere yöntem çözümüne enjekte edebilir:

class SomeBaseClass(object):
    def __init__(self):
        print('SomeBaseClass.__init__(self) called')

class UnsuperChild(SomeBaseClass):
    def __init__(self):
        print('UnsuperChild.__init__(self) called')
        SomeBaseClass.__init__(self)

class SuperChild(SomeBaseClass):
    def __init__(self):
        print('SuperChild.__init__(self) called')
        super(SuperChild, self).__init__()

Nesnenize başka bir sınıf eklediğinizi ve Foo ile Bar arasına bir sınıf enjekte etmek istediğinizi varsayalım (test için veya başka bir nedenden dolayı):

class InjectMe(SomeBaseClass):
    def __init__(self):
        print('InjectMe.__init__(self) called')
        super(InjectMe, self).__init__()

class UnsuperInjector(UnsuperChild, InjectMe): pass

class SuperInjector(SuperChild, InjectMe): pass

Süper olmayan alt öğeyi kullanmak bağımlılığı enjekte edemez, çünkü kullandığınız çocuk kendisinden sonra çağrılacak yöntemi sabit olarak kodlamıştır:

>>> o = UnsuperInjector()
UnsuperChild.__init__(self) called
SomeBaseClass.__init__(self) called

Ancak, alt superöğeyi kullanan sınıf bağımlılığı doğru şekilde enjekte edebilir:

>>> o2 = SuperInjector()
SuperChild.__init__(self) called
InjectMe.__init__(self) called
SomeBaseClass.__init__(self) called

Bir yorumu adresleme

Neden dünyada bu işe yarar?

Python, bir Yöntem Çözünürlük Düzeni (MRO) oluşturmak için C3 doğrusallaştırma algoritması aracılığıyla karmaşık bir miras ağacını doğrusallaştırır .

Yöntemlerin bu sırayla aranmasını istiyoruz .

Bir üst öğede tanımlanmış bir yöntemin bir sonrakini bu sırada superbulunmaması için,

  1. mro örneğinin türünden alın
  2. yöntemi tanımlayan türü arayın
  3. yöntemle bir sonraki türü bul
  4. bu yöntemi bağlayın ve beklenen bağımsız değişkenlerle çağırın

UnsuperChildErişemez olmalıdır InjectMe. Neden "Her zaman kullanmaktan kaçının super" sonucu yok? Burada ne eksik?

UnsuperChildYok değil erişebilir InjectMe. Erişime sahip olan UnsuperInjector, InjectMeancak o sınıfın yöntemini devraldığı yöntemden çağıramaz UnsuperChild.

Hem Çocuk sınıfları olabilir sonraki MRO geliyor aynı adla, bir yöntemini çağırmak niyetinde başka o oluşturulduğu zaman farkında değildi sınıfı.

Kalmadan tek bir supersabit kodları olan ebeveynin yöntem - böylece yöntemin davranışı kısıtladı edilir ve alt sınıfları olabilir çağrısı zinciri olmayan iğne işlevsellik.

Bir ile super daha fazla esneklik vardır. Yöntemler için çağrı zinciri ele geçirilebilir ve işlevsellik enjekte edilebilir.

Bu işlevselliğe ihtiyacınız olmayabilir, ancak kodunuzun alt sınıfları olabilir.

Sonuç

Her zaman superana sınıfı sabit kodlamak yerine başvurmak için kullanın .

Amaçladığınız şey, özellikle çocuğun miras aldığını gördüğünüz sınıftan değil, sıradaki ebeveyn sınıfına başvurmaktır.

Kullanmamak super, kodunuzun kullanıcıları için gereksiz kısıtlamalar getirebilir.


C yılında DI gibidir bu . kodu burada . Bir listarabirim uygulaması daha eklersem, doublylinkedlisto zaman uygulama sorunsuz seçer diyelim . config.txtYüklemede uygulamayı tanıtıp bağlayarak örneğimi daha yapılandırılabilir yapabilirim . Bu doğru örnek mi? Evetse, Kodunuzu nasıl ilişkilendiririm? Wiki'de DI'nin ilk reklamını görün. Yeni uygulama nerede yapılandırılabilir? Kodunuzdaki
overexchange

Örneğin, "Enjektör" sınıflarından birinin sınıftan miras aldığı miras yoluyla yeni bir uygulama oluşturulur InjectMe. Ancak yorumlar tartışma amaçlı değildir, bu yüzden bunu sohbetteki diğer kişilerle daha fazla tartışmanızı veya ana sitede yeni bir soru sormanızı öneririm.
Aaron Hall

mükemmel cevap! ancak çoklu kalıtım kullanırken, super () ve __init__fonksiyonlarla ilgili komplikasyonlar vardır . özellikle imza __init__hiyerarşideki sınıflar arasında değişiyorsa. Bu
konuya

35

Biraz oynamıştım super()ve arama düzenini değiştirebileceğimizi fark etmiştim .

Örneğin, bir sonraki hiyerarşi yapımız var:

    A
   / \
  B   C
   \ /
    D

Bu durumda D'nin MRO değeri (sadece Python 3 için) olacaktır:

In [26]: D.__mro__
Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)

super()Yöntem sınıfından sonra çağrıların yapıldığı bir sınıf oluşturalım .

In [23]: class A(object): #  or with Python 3 can define class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          print("I'm from B")
...:          super().__init__()
...:   
...: class C(A):
...:      def __init__(self):
...:          print("I'm from C")
...:          super().__init__()
...:  
...: class D(B, C):
...:      def __init__(self):
...:          print("I'm from D")
...:          super().__init__()
...: d = D()
...:
I'm from D
I'm from B
I'm from C
I'm from A

    A
   / 
  B  C
    /
    D

Bu yüzden çözünürlük sırasının MRO'dakiyle aynı olduğunu görebiliriz. Ancak super()yöntemin başında çağırdığımızda :

In [21]: class A(object):  # or class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          super().__init__()  # or super(B, self).__init_()
...:          print("I'm from B")
...:   
...: class C(A):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from C")
...:  
...: class D(B, C):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from D")
...: d = D()
...: 
I'm from A
I'm from C
I'm from B
I'm from D

Farklı bir siparişimiz var, MRO demetinin sırasını tersine çevirdi.

    A
   / 
  B  C
    /
    D 

Ek okuma için sonraki cevapları tavsiye ederim:

  1. Süper ile C3 doğrusallaştırma örneği (büyük bir hiyerarşi)
  2. Eski ve yeni stil sınıfları arasında önemli davranış değişiklikleri
  3. Yeni Stil Sınıflarında İç Hikaye

Siparişin neden değiştiğini anlamıyorum. İlk bölüm DBCA olduğunu anlıyorum çünkü D birinci sınıftır, o zaman kendini yüklerken (B, C) sonunda B, C sonra sadece A yazacaktır çünkü B (A), C (A) final için kendini işaret etti Bölüm. Eğer bu anlayışı takip edersem, ikinci kısım BCAD gibi olmamalı mı? Lütfen bana biraz açıklar mısınız?
JJson

Benim hatam, her sınıf örneğinin ilk önce super () ile başlatıldığını fark etmedim. O zaman durum buysa, ABCD olmamalı mı? Bir şekilde ACBD'nin nasıl geldiğini anlıyorum ama hala ikna edemedim ve hala biraz kafam karıştı. benim anlayışım, d = D () 2 öz parametreli Sınıf D (B, C) olarak adlandırılır, çünkü önce super () başlatılır, sonra B öznitelikleriyle birlikte B çağrılır, sonra C sınıftan önce D yazdırılmaz D (B, C) 2 öz parametre içerir, bu nedenle C Sınıfı (A) olan ikincisini yürütmelidir, yürütüldükten sonra yürütülecek daha fazla öz parametre yoktur
JJson

Mro tanımına dayanıyor .
SKhalymon

1
sonra C'yi, sonra B'yi ve son olarak D'yi basacaktır. Haklı mıyım?
JJson

2
Birincisini aldığınız sürece ikincisini anlamak çok kolaydır. Tıpkı bir yığın gibi. baskıyı '' yığına iter ve super () yaparsınız, A bittiğinde, bu yığındaki şeyleri yazdırmaya başlar, böylece sıra ters olur.
güneş verin

35

Bütün bunlar temel sınıfın yeni bir stil sınıfı olduğunu düşünmüyor mu?

class A:
    def __init__(self):
        print("A.__init__()")

class B(A):
    def __init__(self):
        print("B.__init__()")
        super(B, self).__init__()

Python 2'de çalışmaz. class AYeni stil olmalıdır, yani:class A(object)


20

Bir super()ebeveynin bir classmethod, instance yöntemi veya staticmethod sürümüne çözüm bulmak için çağrı yaparken , hangi argümanın kapsamını çözmeye çalıştığımızı belirtmek için, kapsamı ilk argüman olarak içinde bulunduğumuz geçerli sınıfı geçmek istiyoruz. ilgi konusu nesneyi, o kapsamı uygulamaya çalıştığımızı gösteren ikinci bir argüman.

Düşünün bir sınıf hiyerarşisi A, Bve Cher sınıf onu takip eden üstüdür ve burada a, bve cher birinin ayrı ayrı örneklerini.

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

superStatik yöntemle kullanma

örneğin yöntem super()içinden kullanma__new__()

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return super(A, cls).__new__(cls, *a, **kw)

Açıklama:

1- __new__()ilk param olarak çağıran sınıfa başvuru yapmak olağan olsa da , Python'da bir sınıf yöntemi olarak değil , bir statik yöntem olarak uygulanmaktadır. Yani, __new__()doğrudan çağırırken bir sınıfa yapılan başvurunun ilk argüman olarak açıkça iletilmesi gerekir :

# 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- super()Ana sınıfa ulaşmak için çağrıldığında A, ilk argüman olarak alt sınıftan geçiyoruz, sonra ilgilenilen nesneye bir referans geçiyoruz, bu durumda A.__new__(cls)çağrıldığında geçirilen sınıf referansı . Çoğu durumda, alt sınıfa da bir referans olur. Bazı durumlarda, örneğin çoklu nesil miraslar söz konusu olmayabilir.

super(A, cls)

3- Genel bir kural __new__()olarak bir statik yöntem olduğu için, super(A, cls).__new__aynı zamanda bir statik yöntem de döndürür ve bu durumda içsel nesneye yapılan başvuru da dahil olmak üzere tüm argümanların açıkça sağlanması gerekir cls.

super(A, cls).__new__(cls, *a, **kw)

4- Aynı şeyi olmadan yapmak super

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return object.__new__(cls, *a, **kw)

superÖrnek yöntemiyle kullanma

örneğin super()içeriden kullanmak__init__()

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        super(A, self).__init__(*a, **kw)

Açıklama:

1- __init__bir örnek yöntemidir, yani ilk argümanı olarak bir örneğe referans alır. Doğrudan örnekten çağrıldığında, başvuru dolaylı olarak iletilir, yani belirtmeniz gerekmez:

# 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- ararken super()içinde __init__()ilk bağımsız değişken olarak alt sınıf ve genel olarak alt sınıf örneğine referans olan bir ikinci değişken gibi ilgi konusu nesne geçmektedir.

super(A, self)

3- Çağrı super(A, self), kapsamı çözecek ve selfşimdi ana sınıfın bir örneği gibi uygulanacak bir proxy döndürür . Bu proxy'yi diyelim s. Bu yana __init__()bir örnek yöntemi arama s.__init__(...)dolaylı bir referans geçecek selfebeveyne ilk bağımsız olduğu gibi __init__().

4- aynısını yapmadan super, bir örneğe ebeveynin sürümüne açıkça bir referans göndermemiz gerekir __init__().

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        object.__init__(self, *a, **kw)

superSınıf yöntemiyle kullanma

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)

Açıklama:

1- Bir sınıf yöntemi doğrudan sınıftan çağrılabilir ve ilk parametresi olarak sınıfa başvuru alır.

# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()

2- super()bir sınıf içinde ebeveyninin sürümüne çözüm bulmak için çağırırken , hangi alt öğenin çözümlemeye çalıştığımızı belirtmek için geçerli alt sınıfı ilk argüman olarak ve ikinci argüman olarak ilgilenilen nesneyi geçmek istiyoruz. bu kapsamı hangi nesneyi uygulamak istediğimizi belirtmek, ki bu genel olarak alt sınıfın kendisine veya alt sınıflarından birine referanstır.

super(B, cls_or_subcls)

3- Çağrı super(B, cls)kapsamına karar verir Ave bunu uygular cls. Yana alternate_constructor()bir classmethod olan çağrı super(B, cls).alternate_constructor(...)örtük bir başvuru geçecek clsilk argüman olarak Abir bireyin sürümüalternate_constructor()

super(B, cls).alternate_constructor()

4- aynısını kullanmadan yapmak super()için, bağlanmamış sürümüne A.alternate_constructor()(yani fonksiyonun açık sürümüne) bir referans almanız gerekir . Sadece bunu yapmak işe yaramaz:

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)

Yukarıdaki A.alternate_constructor()yöntem işe yaramaz çünkü yöntem Ailk argümanı olarak örtük bir referans alır . clsBuraya gönderilen varlık ikinci argüman olacaktır.

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)

6

Birçok harika cevap, ama görsel öğrenenler için: Öncelikle süper ve sonra olmadan argümanlarla keşfedelim. süper miras ağacı örneği

Resimde yeşil renkte gösterildiği gibi miras zincirine sahip jackolan sınıftan yaratılmış bir örnek olduğunu düşünün Jack. Arayan:

super(Jack, jack).method(...)

jack(miras ağacının belirli bir sırayla) MRO'sunu (Yöntem Çözünürlük Sırası) kullanacak ve aramaya başlayacaktır Jack. Neden bir ebeveyn sınıfı olabilir? Örnekten aramaya başlarsak jack, örnek yöntemini bulur, asıl mesele ebeveyn yöntemini bulmaktır.

Eğer kişi super'e argüman sağlamıyorsa, bu ilk argümanın sınıfıdır selfve ikinci argüman ise self. Bunlar sizin için Python3'te otomatik olarak hesaplanır.

Ancak diyelim ki Jack's yöntemini kullanmak istemiyoruz Jack, içeri Jengirmek yerine, yöntemi yukarı doğru aramaya başlamak için geçebildik Jen.

Her seferinde bir katman arar (genişlik değil genişlik), örneğin her ikisi de gerekli yönteme sahipse Adamve Sueher ikisinde de, önce gelen katman Suebulunur.

Eğer Cainve Sueher ikisi de gerekir yöntemi vardı, Cain'nin metodu ilk olarak adlandırılırdı. Bu, kodun karşılığı:

Class Jen(Cain, Sue):

MRO soldan sağa.


2

burada bazı harika cevaplar var, ancak super()hiyerarşideki farklı sınıfların farklı imzalara sahip olduğu durumlarda nasıl kullanılacağını ele almıyorlar ... özellikle__init__

bu kısmı cevaplamak ve etkin bir şekilde kullanabilmek için super()cevabımı süper () okumayı ve işbirlikçi yöntemlerin imzasını değiştirmenizi öneririm .

İşte bu senaryonun çözümü:

  1. hiyerarşinizdeki üst düzey sınıflar aşağıdaki gibi özel bir sınıftan miras almalıdır SuperObject:
  2. sınıflar farklı bağımsız değişkenler alabilirse, aldığınız tüm bağımsız değişkenleri her zaman süper işleve anahtar kelime bağımsız değişkenleri olarak iletin ve her zaman kabul edin **kwargs.
class SuperObject:        
    def __init__(self, **kwargs):
        print('SuperObject')
        mro = type(self).__mro__
        assert mro[-1] is object
        if mro[-2] is not SuperObject:
            raise TypeError(
                'all top-level classes in this hierarchy must inherit from SuperObject',
                'the last class in the MRO should be SuperObject',
                f'mro={[cls.__name__ for cls in mro]}'
            )

        # super().__init__ is guaranteed to be object.__init__        
        init = super().__init__
        init()

örnek kullanım:

class A(SuperObject):
    def __init__(self, **kwargs):
        print("A")
        super(A, self).__init__(**kwargs)

class B(SuperObject):
    def __init__(self, **kwargs):
        print("B")
        super(B, self).__init__(**kwargs)

class C(A):
    def __init__(self, age, **kwargs):
        print("C",f"age={age}")
        super(C, self).__init__(age=age, **kwargs)

class D(B):
    def __init__(self, name, **kwargs):
        print("D", f"name={name}")
        super(D, self).__init__(name=name, **kwargs)

class E(C,D):
    def __init__(self, name, age, *args, **kwargs):
        print( "E", f"name={name}", f"age={age}")
        super(E, self).__init__(name=name, age=age, *args, **kwargs)

E(name='python', age=28)

çıktı:

E name=python age=28
C age=28
A
D name=python
B
SuperObject

0
class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

Bunu anlamak oldukça kolaydır.

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

Tamam, şimdi kullanırsan ne olur super(Child,self)?

Bir Child örneği oluşturulduğunda, MRO'su (Yöntem Çözüm Sırası) mirasa dayalı olarak (Child, SomeBaseClass, nesne) sırasına göre sıralanır. (SomeBaseClass öğesinin varsayılan nesne dışında başka ebeveynleri olmadığını varsayalım)

Geçerek Child, self, superbir MRO aramaları selfbu durumda 's SomeBaseClass içinde, bir sonraki Çocuk vekil nesne örneğine ve iade, bu nesne daha sonra çağıran __init__SomeBaseClass yöntemini. Başka bir super(SomeBaseClass,self)deyişle , eğer öyleyse , superdöndüren proxy nesnesiobject

Çoklu kalıtım için, MRO birçok sınıf içerebilir, bu nedenle temel olarak superMRO'da nerede aramaya başlamak istediğinize karar vermenizi sağlar.


0

Aşağıdaki kodu göz önünde bulundurun:

class X():
    def __init__(self):
        print("X")

class Y(X):
    def __init__(self):
        # X.__init__(self)
        super(Y, self).__init__()
        print("Y")

class P(X):
    def __init__(self):
        super(P, self).__init__()
        print("P")

class Q(Y, P):
    def __init__(self):
        super(Q, self).__init__()
        print("Q")

Q()

Değişikliği yapıcısı varsa Yiçin X.__init__, alırsınız:

X
Y
Q

Ama kullanarak super(Y, self).__init__(), alacaksınız:

X
P
Y
Q

Ve Pya Qhatta yazarken Bilmiyorsanız başka bir dosyadan dahil olabilir Xve Y. Yani, temel olarak, yazarken neye super(Child, self)başvuracağınızı bilemezsiniz class Y(X), hatta Y imzası bile basittir Y(X). Bu yüzden süper daha iyi bir seçim olabilir.

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.