Jak zainicjować klasę podstawową (super)?

126

W Pythonie weźmy pod uwagę następujący kod:

>>> class SuperClass(object):
    def __init__(self, x):
        self.x = x

>>> class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y
        # how do I initialize the SuperClass __init__ here?

Jak zainicjować SuperClass __init__w podklasie? Postępuję zgodnie z samouczkiem Pythona i nie obejmuje tego. Kiedy szukałem w Google, znalazłem więcej niż jeden sposób. Jaki jest standardowy sposób radzenia sobie z tym?

Jeremy
źródło

Odpowiedzi:

147

Python (do wersji 3) obsługuje klasy „w starym” i nowym stylu. Klasy w nowym stylu pochodzą od objecti są tym, czego używasz, i wywołują ich klasę bazową za pośrednictwem super(), np

class X(object):
  def __init__(self, x):
    pass

  def doit(self, bar):
    pass

class Y(X):
  def __init__(self):
    super(Y, self).__init__(123)

  def doit(self, foo):
    return super(Y, self).doit(foo)

Ponieważ Python wie o klasach w starym i nowym stylu, istnieją różne sposoby wywoływania metody bazowej, dlatego znalazłeś wiele sposobów, aby to zrobić.

Ze względu na kompletność klasy w starym stylu wywołują metody bazowe jawnie przy użyciu klasy bazowej, tj

def doit(self, foo):
  return X.doit(self, foo)

Ale ponieważ nie powinieneś już używać starego stylu, nie przejmowałbym się tym zbytnio.

Python 3 wie tylko o klasach w nowym stylu (bez względu na to, czy pochodzisz, objectczy nie).

Ivo van der Wijk
źródło
38

Obie

SuperClass.__init__(self, x)

lub

super(SubClass,self).__init__( x )

zadziała (wolę ten drugi, ponieważ bardziej odpowiada zasadzie DRY).

Zobacz tutaj: http://docs.python.org/reference/datamodel.html#basic-customization

adamk
źródło
8
źle. super działa tylko z klasami w nowym stylu i jest jedynym właściwym sposobem wywołania bazy podczas używania klas w nowym stylu. Co więcej, musisz również jawnie przekazać „self”, używając konstrukcji w starym stylu.
Ivo van der Wijk
1
@Ivo - OP dał klasę nowego stylu w tym przykładzie i nie ma sensu mówić o różnicy między nowym i starym stylem, ponieważ nikt nie powinien już używać starego stylu. Link, który podałem (do dokumentacji Pythona) sugeruje, że istnieje więcej niż jeden „właściwy” sposób na wywołanie superklasy __init__.
adamk
21

Jak zainicjować klasę podstawową (super)?

class SuperClass(object):
    def __init__(self, x):
        self.x = x

class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y

Użyj superobiektu, aby upewnić się, że otrzymasz następną metodę (jako metodę powiązaną) w kolejności rozwiązywania metod. W Pythonie 2 musisz przekazać nazwę klasy i selfsuper, aby wyszukać powiązaną __init__metodę:

 class SubClass(SuperClass):
      def __init__(self, y):
          super(SubClass, self).__init__('x')
          self.y = y

W Pythonie 3 jest trochę magii, która sprawia, że ​​argumenty są superniepotrzebne - i jako korzyść uboczna działa trochę szybciej:

 class SubClass(SuperClass):
      def __init__(self, y):
          super().__init__('x')
          self.y = y

Zakodowanie rodzica w następujący sposób zapobiega korzystaniu z wielokrotnego dziedziczenia w trybie współpracy:

 class SubClass(SuperClass):
      def __init__(self, y):
          SuperClass.__init__(self, 'x') # don't do this
          self.y = y

Zauważ, że __init__może tylko powrócićNone - ma na celu modyfikację obiektu w miejscu.

Coś __new__

Istnieje inny sposób inicjowania instancji - i jest to jedyny sposób na podklasy niezmiennych typów w Pythonie. Więc nie jest to wymagane, jeśli chcesz podklasy strlub tuplelub innego niezmiennego obiektu.

Możesz pomyśleć, że jest to metoda klasowa, ponieważ pobiera niejawny argument klasy. Ale w rzeczywistości jest to metoda statyczna . Więc musisz jawnie zadzwonić __new__z cls.

Zwykle zwracamy instancję z __new__, więc jeśli to zrobisz, musisz również zadzwonić do swojej bazy przez __new__via superw swojej klasie bazowej. Więc jeśli używasz obu metod:

class SuperClass(object):
    def __new__(cls, x):
        return super(SuperClass, cls).__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super(SubClass, cls).__new__(cls)

    def __init__(self, y):
        self.y = y
        super(SubClass, self).__init__('x')

Python 3 omija trochę dziwaczności super wywołań spowodowanych tym, __new__że jest metodą statyczną, ale nadal musisz przejść clsdo metody niezwiązanej __new__:

class SuperClass(object):
    def __new__(cls, x):
        return super().__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super().__new__(cls)
    def __init__(self, y):
        self.y = y
        super().__init__('x')
Aaron Hall
źródło