Python ile genişletme - super () Python 3 ve Python 2 kullanarak


103

Başlangıçta bu soruyu sormak istedim , ancak daha önce düşünülmüş olduğunu anladım ...

Googling, bu configparser'ı genişletme örneğini buldum . Aşağıdakiler Python 3 ile çalışır:

$ python3
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2
>>> from configparser import  SafeConfigParser
>>> class AmritaConfigParser(SafeConfigParser):
...     def __init_(self):
...         super().__init__()
... 
>>> cfg = AmritaConfigParser()

Ancak Python 2 ile değil:

>>> class AmritaConfigParser(SafeConfigParser):
...       def __init__(self):
...           super(SafeConfigParser).init()
... 
>>> cfg = AmritaConfigParser()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: must be type, not classob

Sonra biraz Python Yeni Sınıf ve Eski Sınıf stilleri okudum (örneğin burada . Ve şimdi merak ediyorum, şunları yapabilirim:

class MyConfigParser(ConfigParser.ConfigParser):
      def Write(self, fp):
          """override the module's original write funcition"""
          ....
      def MyWrite(self, fp):
          """Define new function and inherit all others"""

Ama init'i aramamalı mıyım? Bu Python 2'de eşdeğer mi:

 class AmritaConfigParser(ConfigParser.SafeConfigParser):
    #def __init__(self):
    #    super().__init__() # Python3 syntax, or rather, new style class syntax ...
    #
    # is this the equivalent of the above ? 
    def __init__(self):
        ConfigParser.SafeConfigParser.__init__(self)

1
__init__()Örneğinizde, tek yaptığı şey süper sınıfı ' __init__()(Python 2 veya 3'te) çağırmaksa, alt sınıfta bir tanımlamanıza gerek yoktur - bunun yerine sadece üst sınıfın miras alınmasına izin verin.
martineau


Düzeltilmiş bağlantı ile faydalı referans: amyboyle.ninja/Python-Inheritance
fearless_fool

Yanıtlar:


155
  • super()(bağımsız değişkenler olmadan) Python 3'te (bununla birlikte __class__) tanıtıldı :

    super() -> same as super(__class__, self)

    bu, yeni stil sınıfları için Python 2 eşdeğeri olacaktır:

    super(CurrentClass, self)
  • eski tarz sınıflar için her zaman kullanabilirsiniz:

     class Classname(OldStyleParent):
        def __init__(self, *args, **kwargs):
            OldStyleParent.__init__(self, *args, **kwargs)

8
-1. Bu cevap benim için hiçbir şeyi netleştirmedi. Python 2'de super(__class__)verir NameError: global name '__class__' is not definedve super(self.__class__)aynı zamanda hatalıdır. Yapmanız gerektiğini düşündüren ikinci bir argüman olarak bir örnek sağlamalısınız super(self.__class__, self), ancak bu yanlıştır . Eğer Class2devralır Class1ve Class1çağrıların super(self.__class__, self).__init__(), Class1'ın __init__ardından edecek kendisini aramak örneği başlatılırken zaman Class2.
jpmc26

Bir noktayı açıklığa kavuşturmak için, benim hemen TypeError: super() takes at least 1 argument (0 given)aramaya çalışırken super(self.__class__)Python 2. (anlamda çok yapmaz, ama bu cevap eksik ne kadar bilgi o gösterir.)
jpmc26

3
@ jpmc26: senin aramaya çalışıyorum çünkü python2 içinde bu hatayı __init__()(eğer arayarak olsun bağlanmamış süper nesne üzerinde argüman olmadan super(self.__class__)tek argümanı ile), daha sonra da çalışması gerektiğini bir sınır süper nesnesi gerekir: super(CurrentClass, self).__init__(). Bir ebeveyn çağırırken self.__class__bu her zaman aynı sınıfa atıfta bulunacağı için kullanmayın ve bu nedenle ebeveyn de aynı şeyi yaparsa sonsuz bir döngü oluşturun.
mata

__class__(üye) Python2'de de mevcuttur .
CristiFati

3
@CristiFati Bu __class__üye ile ilgili değil, her zaman şu anda tanımlanmış olan sınıfa atıfta bulunan ve python2'de bulunmayan örtük olarak oluşturulan sözcüksel __class__kapanışla ilgilidir.
mata

49

Tek bir miras durumunda (yalnızca bir sınıfı alt sınıflara ayırdığınızda), yeni sınıfınız temel sınıfın yöntemlerini miras alır. Bu içerir __init__. Yani sınıfınızda tanımlamazsanız, temelden bir tane alacaksınız.

Birden fazla kalıtım getirirseniz (bir seferde birden fazla sınıfı alt sınıflara ayırmak) işler karmaşıklaşmaya başlar. Bunun nedeni, birden fazla temel sınıfa sahipse __init__, sınıfınızın yalnızca ilkini miras almasıdır.

Böyle durumlarda gerçekten kullanmalısınız, supereğer yapabiliyorsanız, nedenini açıklayacağım. Ama her zaman yapamazsın. Sorun şu ki, tüm temel sınıflarınız da onu (ve onların temel sınıfları da - tüm ağacı) kullanmalıdır.

Durum böyleyse, bu da doğru şekilde çalışacaktır (Python 3'te ancak Python 2'de yeniden çalışabilirsiniz - ayrıca vardır super):

class A:
    def __init__(self):
        print('A')
        super().__init__()

class B:
    def __init__(self):
        print('B')
        super().__init__()

class C(A, B):
    pass

C()
#prints:
#A
#B

Her iki temel sınıfın superkendi temel sınıfları olmasa bile nasıl kullandığına dikkat edin .

Ne superyapar: MRO'daki bir sonraki sınıftan yöntemi çağırır (yöntem çözümleme sırası). İçin MRO Cgeçerli: (C, A, B, object). C.__mro__Görmek için yazdırabilirsiniz .

Yani, Cdevralır __init__gelen Ave superiçinde A.__init__çağrıların B.__init__( Başağıda AMRO olarak).

Yani içinde hiçbir şey Cyapmazsanız, ikisini de ararsınız, ki bu da istediğiniz şeydir.

Şimdi kullanmıyor superolsaydın, A.__init__(daha önce olduğu gibi) miras alırdın ama bu sefer B.__init__seni çağıracak hiçbir şey yok .

class A:
    def __init__(self):
        print('A')

class B:
    def __init__(self):
        print('B')

class C(A, B):
    pass

C()
#prints:
#A

Bunu düzeltmek için şunları tanımlamanız gerekir C.__init__:

class C(A, B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)

Bununla ilgili sorun, daha karmaşık MI ağaçlarında, __init__bazı sınıfların yöntemlerinin birden fazla çağrılırken, süper / MRO'nun yalnızca bir kez çağrıldıklarını garanti etmesidir.


10
Notice how both base classes use super even though they don't have their own base classes.Onlar sahip. Py3k'de her sınıf alt sınıf nesnesi.
akaRem

Aradığım cevap buydu, ama nasıl soracağımı bilmiyordum. MRO tanımı iyidir.
dturvene

27

Kısaca eşdeğerdirler. Bir geçmiş görüşüne sahip olalım:

(1) ilk başta, işlev şöyle görünür.

    class MySubClass(MySuperClass):
        def __init__(self):
            MySuperClass.__init__(self)

(2) kodu daha soyut (ve daha taşınabilir) hale getirmek. Super-Class edinmenin yaygın bir yöntemi şu şekildedir:

    super(<class>, <instance>)

Ve init işlevi şunlar olabilir:

    class MySubClassBetter(MySuperClass):
        def __init__(self):
            super(MySubClassBetter, self).__init__()

Bununla birlikte, hem sınıfın hem de örneğin açık bir şekilde geçmesini zorunlu kılmak, DRY (Kendini Tekrar Etme) kuralını biraz bozar.

(3) V3'te. Daha akıllı

    super()

çoğu durumda yeterlidir. Http://www.python.org/dev/peps/pep-3135/ adresine başvurabilirsiniz.


22

Şimdi çoğu insanın kullandığı anlaşılan Python 3 için basit ve eksiksiz bir örneğe sahip olmak için.

class MySuper(object):
    def __init__(self,a):
        self.a = a

class MySub(MySuper):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)

my_sub = MySub(42,'chickenman')
print(my_sub.a)
print(my_sub.b)

verir

42
chickenman

3

Abstract sınıflarının super () ile kullanılmasını içeren başka bir python3 uygulaması. Bunu hatırlamalısın

super().__init__(name, 10)

ile aynı etkiye sahiptir

Person.__init__(self, name, 10)

Super () 'de gizli bir' benlik 'olduğunu hatırlayın, böylece aynı nesne süper sınıf başlatma yöntemine geçer ve nitelikler onu çağıran nesneye eklenir. Bu nedenle super()çevrilir Personve sonra gizli benliği eklerseniz, yukarıdaki kod parçasını alırsınız.

from abc import ABCMeta, abstractmethod
class Person(metaclass=ABCMeta):
    name = ""
    age = 0

    def __init__(self, personName, personAge):
        self.name = personName
        self.age = personAge

    @abstractmethod
    def showName(self):
        pass

    @abstractmethod
    def showAge(self):
        pass


class Man(Person):

    def __init__(self, name, height):
        self.height = height
        # Person.__init__(self, name, 10)
        super().__init__(name, 10)  # same as Person.__init__(self, name, 10)
        # basically used to call the superclass init . This is used incase you want to call subclass init
        # and then also call superclass's init.
        # Since there's a hidden self in the super's parameters, when it's is called,
        # the superclasses attributes are a part of the same object that was sent out in the super() method

    def showIdentity(self):
        return self.name, self.age, self.height

    def showName(self):
        pass

    def showAge(self):
        pass


a = Man("piyush", "179")
print(a.showIdentity())
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.