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)
và D(B)
và 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 a
và b
trường hợp của A
và B
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.a
và self.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.
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
@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ó. –
@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. –