Bagaimana cara menginisialisasi kelas dasar (super)?

126

Dengan Python, pertimbangkan saya memiliki kode berikut:

>>> 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?

Bagaimana cara saya menginisialisasi SuperClass __init__subclass? Saya mengikuti tutorial Python dan tidak mencakup itu. Ketika saya mencari di Google, saya menemukan lebih dari satu cara untuk melakukannya. Bagaimana cara standar menangani ini?

Jeremy
sumber

Jawaban:

147

Python (hingga versi 3) mendukung kelas "gaya lama" dan gaya baru. Kelas gaya baru diturunkan dari objectdan merupakan apa yang Anda gunakan, dan memanggil kelas dasarnya melalui super(), misalnya

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)

Karena python tahu tentang kelas gaya lama dan baru, ada berbagai cara untuk memanggil metode dasar, itulah sebabnya Anda menemukan banyak cara untuk melakukannya.

Demi kelengkapan, kelas gaya lama memanggil metode dasar secara eksplisit menggunakan kelas dasar, yaitu

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

Tetapi karena Anda seharusnya tidak menggunakan gaya lama lagi, saya tidak akan terlalu peduli tentang ini.

Python 3 hanya tahu tentang kelas gaya baru (tidak peduli apakah Anda berasal objectatau tidak).

Ivo van der Wijk
sumber
38

Kedua

SuperClass.__init__(self, x)

atau

super(SubClass,self).__init__( x )

akan bekerja (Saya lebih suka yang kedua, karena lebih menganut prinsip KERING).

Lihat di sini: http://docs.python.org/reference/datamodel.html#basic-customization

adamk
sumber
8
salah. super hanya berfungsi dengan kelas gaya baru, dan merupakan satu-satunya cara yang tepat untuk memanggil basis saat menggunakan kelas gaya baru. Selain itu, Anda juga perlu meneruskan 'self' secara eksplisit menggunakan konstruksi gaya lama.
Ivo van der Wijk
1
@Ivo - OP memberikan kelas gaya baru dalam contoh, dan tidak ada gunanya membicarakan perbedaan antara gaya baru dan gaya lama karena tidak ada lagi yang boleh menggunakan gaya lama. Tautan yang saya berikan (ke dokumen Python) menunjukkan bahwa ada lebih dari satu cara yang "tepat" untuk memanggil super-class __init__.
adamk
21

Bagaimana cara menginisialisasi kelas dasar (super)?

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

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

Gunakan superobjek untuk memastikan Anda mendapatkan metode berikutnya (sebagai metode terikat) dalam urutan resolusi metode. Di Python 2, Anda harus meneruskan nama kelas dan selfke super untuk mencari __init__metode terikat :

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

Di Python 3, ada sedikit keajaiban yang membuat argumen menjadi supertidak perlu - dan sebagai manfaat tambahannya bekerja sedikit lebih cepat:

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

Melakukan hardcode induk seperti ini di bawah ini mencegah Anda menggunakan multiple inheritance kooperatif:

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

Perhatikan bahwa __init__mungkin hanya mengembalikanNone - ini dimaksudkan untuk mengubah objek di tempat.

Sesuatu __new__

Ada cara lain untuk menginisialisasi instance - dan ini satu-satunya cara untuk subclass dari tipe yang tidak dapat diubah dengan Python. Jadi diperlukan jika Anda ingin membuat subclass stratau tupleobjek tetap lainnya.

Anda mungkin mengira itu metode kelas karena mendapat argumen kelas implisit. Tapi sebenarnya itu metode statis . Jadi Anda perlu menelepon __new__dengan clseksplisit.

Kami biasanya mengembalikan instance from __new__, jadi jika Anda melakukannya, Anda juga perlu memanggil basis Anda __new__via superjuga di kelas dasar Anda. Jadi jika Anda menggunakan kedua metode tersebut:

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 menghindari sedikit keanehan panggilan super yang disebabkan oleh __new__metode statis, tetapi Anda masih perlu meneruskan clske metode tidak terikat __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
sumber