2009-05-24 36 views
242

Xem xét điều này - một lớp cơ sở A, lớp B kế thừa từ A, lớp C kế thừa từ B. Cách tổng quát để gọi hàm tạo lớp cha trong một hàm tạo là gì? Nếu điều này vẫn còn quá mơ hồ, đây là một số mã.Trình xây dựng cha mẹ gọi chuỗi trong python

class A(object): 
    def __init__(self): 
     print "Constructor A was called" 

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

class C(B): 
    def __init__(self): 
     super(C,self).__init__() 
     print "Constructor C was called" 

c = C() 

Đây là cách tôi làm ngay bây giờ. Nhưng nó vẫn có vẻ hơi quá chung chung - bạn vẫn phải vượt qua một loại chính xác bằng tay. Bây giờ, tôi đã thử sử dụng self.__class__ làm đối số đầu tiên cho siêu(), nhưng, rõ ràng là nó không hoạt động - nếu bạn đặt nó trong hàm tạo cho C - đủ công bằng, hàm tạo của B được gọi. Nếu bạn làm như vậy trong B, "self" vẫn trỏ đến một thể hiện của C để bạn kết thúc gọi hàm khởi tạo của B một lần nữa (điều này kết thúc bằng một đệ quy vô hạn).

Không cần phải suy nghĩ về kế thừa kim cương cho bây giờ, tôi chỉ quan tâm đến việc giải quyết vấn đề cụ thể này.

+0

"Nhưng nó vẫn có vẻ hơi quá phi generic - bạn vẫn phải vượt qua một loại chính xác bằng tay. "?? Bạn đang chuyển tên lớp thành super(). Bạn không bao giờ cần biết siêu lớp hay bất cứ thứ gì khác. Làm thế nào là không chung chung này? Nó tạo ra vấn đề gì? Bạn có thể đưa ra một ví dụ trong đó điều này bị phá vỡ không? –

+3

Tôi chưa sẵn sàng trả lời câu hỏi này nếu đầy đủ. Nhưng dù sao thì, nếu lớp học được đổi tên thì sao? Điều gì sẽ xảy ra nếu tôi muốn viết một hàm trang trí để tự động hóa kiểu chuỗi này? Bây giờ tôi thấy, rằng điều này là không thể, nhưng tại thời điểm đặt câu hỏi tôi không biết điều đó. – shylent

Trả lời

151

Cách bạn đang thực sự thực sự là khuyến nghị (đối với Python 2.x).

Vấn đề liệu lớp học có được chuyển một cách rõ ràng đến super là vấn đề về phong cách thay vì chức năng hay không. Chuyển lớp học sang super phù hợp với triết lý "rõ ràng là tốt hơn là ngầm" của Python.

+3

Tôi đã có một thời gian thực sự khó khăn quyết định câu trả lời để chấp nhận, nhưng tôi sẽ chấp nhận điều này, đơn giản chỉ vì nó có liên quan đến phiên bản python mà tôi đang sử dụng. – shylent

+9

Trong Python 2.6, tôi nhận được 'TypeError: super() đối số 1 phải là kiểu, không phải classobj' sử dụng phương thức này. Tui bỏ lỡ điều gì vậy? – Leopd

+12

@Leopd: 'super()' chỉ hoạt động với các lớp kiểu mới, tức là bạn phải kế thừa từ 'đối tượng'. –

159

Python 3 bao gồm một siêu được cải thiện() cho phép sử dụng như thế này:

super().__init__(args) 
+0

nếu tôi có nhiều hơn một lớp cha mẹ sẽ như thế nào siêu xác định các lớp cha mẹ để gọi? – Kracekumar

+2

@kracekumar Nó sẽ được xác định bởi thứ tự Độ phân giải phương thức của lớp (MRO), mà bạn có thể tìm ra bằng cách gọi 'MyClassName.mro()'. Tôi có thể không chính xác, nhưng tôi tin rằng người cha được chỉ định đầu tiên là người có '__init__' sẽ được gọi. –

+0

@ironfroggy, bạn có phiền không về việc làm thế nào để cải tiến siêu trợ giúp này với câu hỏi? Tôi chỉ tìm thấy chuỗi cũ này và tôi có cùng một câu hỏi chính xác. Cũng có những thứ được cải thiện cho Python 2.x vì câu hỏi này được hỏi lần đầu tiên? –

22

Bạn chỉ có thể viết:

class A(object): 

    def __init__(self): 
     print "Constructor A was called" 

class B(A): 

    def __init__(self): 
     A.__init__(self) 
     # A.__init__(self,<parameters>) if you want to call with parameters 
     print "Constructor B was called" 

class C(B): 

    def __init__(self): 
     # A.__init__(self) # if you want to call most super class... 
     B.__init__(self) 
     print "Constructor C was called" 
Các vấn đề liên quan