2013-08-01 34 views
11
class A(): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

class B(): 
    def __init__(self, z=0): 
     self.z = z 

class AB(A,B): 
    def __init__(self, x, y, z=0): 
     ? 

Làm cách nào để hàm tạo AB gọi các hàm tạo cho A và B với các đối số thích hợp?Gọi các hàm tạo siêu lớp trong python với các đối số khác nhau

Tôi đã thử

class AB(A,B): 
    def __init__(self, x, y, z=0): 
     A.__init__(x,y) 
     B.__init__(z) 

nhưng điều này mang lại cho tôi một lỗi.

+1

Tại sao bạn sử dụng thừa kế ở đây thay vì ủy quyền? Bởi vì trường hợp của nhiều thừa kế nên được xử lý bằng cách sử dụng 'super', mà sẽ không hoạt động tốt vì các tham số khác nhau trong' __init__'. – ovgolovin

+2

@ovgolovin Vì tôi là một lập trình viên thiếu kinh nghiệm. Tôi không biết phái đoàn là gì. Tôi sẽ cố gắng nhìn vào nó. –

+0

@ovgolovin Cảm ơn. Hóa ra tôi đã giải quyết vấn đề của mình bằng một trình bao bọc. –

Trả lời

11

Bạn không vượt qua self.

class AB(A, B): 
    def __init__(self, x, y, z=0): 
     A.__init__(self, x, y) 
     B.__init__(self, z) 

Lưu ý rằng nếu phân cấp thừa kế này phức tạp hơn, bạn sẽ gặp vấn đề với các nhà thầu không thực thi hoặc bị xem xét lại. Hãy xem xét super (và problems với super) và đừng quên kế thừa từ object nếu bạn ở trên 2.x và lớp học của bạn không kế thừa từ bất kỳ điều gì khác.

+0

Agh, rất câm. cảm ơn bạn. –

10

Câu trả lời khác đề xuất thêm self vào tham số đầu tiên.

Nhưng thường yêu cầu __init__ trong lớp cha được tạo bởi super.

Hãy xem xét ví dụ sau:

class A(object): 
    def __init__(self, x): 
     print('__init__ is called in A') 
     self.x = x 


class B(object): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in B') 
     super(B, self).__init__(*args, **kwargs) 


class AB(B, A): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in AB') 
     super(AB, self).__init__(*args, **kwargs) 

AB lớp chứa một thứ tự mà nhà thầu và initializators nên được gọi là:

>>> AB.__mro__ 
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>) 

Xem, điều trước tiên AB 's __init__ được gọi, sau đó B' s, sau đó là A và sau đó là object.

Hãy kiểm tra:

>>> ab = AB(1) 
__init__ is called in AB 
__init__ is called in B 
__init__ is called in A 

Nhưng những cuộc gọi thông qua chuỗi này được thực hiện bởi super. Khi chúng tôi nhập super(AB, self), điều đó có nghĩa là: sau đó tìm thấy lớp tiếp theo sau AB trong số __mro__ chuỗi self.

Sau đó, chúng tôi sẽ gọi super trong B, tìm kiếm lớp tiếp theo trong chuỗi sau B: super(B, self).

Điều quan trọng là sử dụng super và không gọi theo cách thủ công A.__init__(self,...), v.v. vì có thể dẫn đến sự cố sau này. Read this for more info.

Vì vậy, nếu bạn gắn bó với super thì có sự cố. Các phương thức __init__ trong các lớp của bạn mong đợi các tham số khác nhau. Và bạn không thể biết chắc chắn thứ tự trong đó super sẽ gọi các phương thức trong các lớp này. Thứ tự được xác định bởi C3 algorithm tại thời điểm tạo lớp học. Trong các lớp con, các lớp khác có thể nhận được ở giữa của chuỗi cuộc gọi. Vì vậy, bạn không thể có các tham số khác nhau trong __init__, như trong trường hợp này, bạn sẽ luôn luôn xem xét tất cả các chuỗi thừa kế để hiểu cách thức các phương thức __init__ sẽ được gọi.

Ví dụ: xem xét thêm các lớp C(A)D(B)CD phân lớp của chúng. Sau đó, A sẽ không còn được gọi sau B, nhưng sau C.

class A(object): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in A') 
     super(A, self).__init__(*args, **kwargs) 


class B(object): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in B') 
     super(B, self).__init__(*args, **kwargs) 

class AB(B,A): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in AB') 
     super(AB, self).__init__(*args, **kwargs) 

class C(A): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in C') 
     super(C, self).__init__(*args, **kwargs) 

class D(B): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in D') 
     super(D, self).__init__(*args, **kwargs) 


class CD(D,C): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in CD') 
     super(CD, self).__init__(*args, **kwargs) 

class ABCD(CD,AB): 
    def __init__(self, *args, **kwargs): 
     print('__init__ is called in ABCD') 
     super(ABCD, self).__init__(*args, **kwargs) 




>>> abcd = ABCD() 
__init__ is called in ABCD 
__init__ is called in CD 
__init__ is called in D 
__init__ is called in AB 
__init__ is called in B 
__init__ is called in C 
__init__ is called in A 

Vì vậy, tôi nghĩ bạn nên suy nghĩ về việc sử dụng delegation thay vì thừa kế tại đây.

class AB(object): 
    def __init__(self, x, y, z=0): 
     self.a = A(x,y) 
     self.b = B(z) 

Vì vậy, bạn chỉ cần tạo ab trường hợp của AB lớp bên AB đối tượng. Và sau đó có thể sử dụng chúng khi bạn cần thông qua các phương pháp bằng cách tham chiếu đến self.aself.b.

Để sử dụng hoặc không ủy quyền phụ thuộc vào trường hợp của bạn không rõ ràng trong câu hỏi của bạn. Nhưng nó có thể là một lựa chọn để xem xét.

Các vấn đề liên quan