Làm cách nào để khởi tạo lớp cơ sở (siêu)?


126

Trong Python, hãy xem xét tôi có mã sau:

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

Làm cách nào để khởi tạo SuperClass __init__lớp con trong lớp? Tôi đang làm theo hướng dẫn Python và nó không bao gồm điều đó. Khi tôi tìm kiếm trên Google, tôi tìm thấy nhiều cách làm. Cách tiêu chuẩn để xử lý điều này là gì?

Câu trả lời:


147

Python (cho đến phiên bản 3) hỗ trợ các lớp "kiểu cũ" và lớp kiểu mới. Các lớp kiểu mới có nguồn gốc từ objectvà là những gì bạn đang sử dụng và gọi lớp cơ sở của chúng thông qua super(), ví dụ:

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)

Vì python biết về các lớp kiểu cũ và kiểu mới nên có nhiều cách khác nhau để gọi một phương thức cơ sở, đó là lý do tại sao bạn đã tìm thấy nhiều cách để làm như vậy.

Vì lợi ích hoàn chỉnh, các lớp kiểu cũ gọi các phương thức cơ sở một cách rõ ràng bằng cách sử dụng lớp cơ sở, tức là

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

Nhưng vì bạn không nên sử dụng kiểu cũ nữa, tôi sẽ không quan tâm đến điều này quá nhiều.

Python 3 chỉ biết về các lớp kiểu mới (bất kể bạn có bắt nguồn từ đó objecthay không).


38

Cả hai

SuperClass.__init__(self, x)

hoặc là

super(SubClass,self).__init__( x )

sẽ hoạt động (tôi thích cái thứ 2 hơn, vì nó tuân thủ nguyên tắc DRY nhiều hơn).

Xem tại đây: http://docs.python.org/reference/datamodel.html#basic-customization


8
Sai lầm. super chỉ hoạt động với các lớp kiểu mới và là cách thích hợp duy nhất để gọi một cơ sở khi sử dụng các lớp kiểu mới. Hơn nữa, bạn cũng cần phải chuyển 'self' một cách rõ ràng bằng cách sử dụng cấu trúc kiểu cũ.
Ivo van der Wijk

1
@Ivo - OP đã đưa ra một lớp kiểu mới trong ví dụ và có rất ít điểm khi nói về sự khác biệt giữa kiểu mới và kiểu cũ vì không ai nên sử dụng kiểu cũ nữa. Liên kết mà tôi đưa ra (đến các tài liệu Python) gợi ý rằng có nhiều cách "thích hợp" để gọi siêu lớp __init__.
adamk


21

Làm cách nào để khởi tạo lớp cơ sở (siêu)?

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

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

Sử dụng một superđối tượng để đảm bảo bạn nhận được phương thức tiếp theo (dưới dạng phương thức bị ràng buộc) theo thứ tự phân giải phương thức. Trong Python 2, bạn cần chuyển tên lớp và selfsiêu để tra cứu __init__phương thức liên kết :

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

Trong Python 3, có một chút ma thuật làm cho các đối số trở nên superkhông cần thiết - và như một lợi ích phụ, nó hoạt động nhanh hơn một chút:

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

Mã cứng gốc như thế này dưới đây ngăn bạn sử dụng đa kế thừa hợp tác:

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

Lưu ý rằng __init__chỉ có thể quay trở lạiNone - nó nhằm mục đích sửa đổi đối tượng tại chỗ.

Cái gì đó __new__

Có một cách khác để khởi tạo các thể hiện - và đó là cách duy nhất cho các lớp con của các kiểu bất biến trong Python. Vì vậy, nó là bắt buộc nếu bạn muốn phân lớp con strhoặc tuplehoặc một đối tượng bất biến khác.

Bạn có thể nghĩ đó là một phương pháp phân lớp vì nó nhận được một đối số lớp ngầm. Nhưng nó thực sự là một staticmethod . Vì vậy, bạn cần phải gọi __new__với clsmột cách rõ ràng.

Chúng tôi thường trả về trường hợp từ __new__, vì vậy nếu bạn làm vậy, bạn cũng cần gọi cơ sở của mình __new__qua supercũng như trong lớp cơ sở của bạn. Vì vậy, nếu bạn sử dụng cả hai phương pháp:

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 vượt qua một chút sự kỳ lạ của các lệnh gọi siêu gây ra bởi __new__là một phương thức tĩnh, nhưng bạn vẫn cần chuyển clsđến __new__phương thức không bị ràng buộc :

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')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.