Đây là chi tiết với số lượng chi tiết hợp lý của chính Guido trong bài đăng trên blog Phương thức giải quyết Phương thức (bao gồm hai lần thử trước đó).
Trong ví dụ của bạn, Third()
sẽ gọi First.__init__
. Python tìm kiếm từng thuộc tính trong lớp cha mẹ của lớp khi chúng được liệt kê từ trái sang phải. Trong trường hợp này, chúng tôi đang tìm kiếm __init__
. Vì vậy, nếu bạn xác định
class Third(First, Second):
...
Python sẽ bắt đầu bằng cách nhìn vào First
, và, nếu First
không có thuộc tính, thì nó sẽ xem xét Second
.
Tình huống này trở nên phức tạp hơn khi kế thừa bắt đầu băng qua các đường dẫn (ví dụ nếu First
được kế thừa từ Second
). Đọc liên kết ở trên để biết thêm chi tiết, nhưng, tóm lại, Python sẽ cố gắng duy trì thứ tự mỗi lớp xuất hiện trong danh sách thừa kế, bắt đầu với chính lớp con.
Vì vậy, ví dụ, nếu bạn có:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
MRO sẽ là [Fourth, Second, Third, First].
Nhân tiện: nếu Python không thể tìm thấy thứ tự phân giải phương thức mạch lạc, nó sẽ đưa ra một ngoại lệ, thay vì quay trở lại hành vi có thể gây ngạc nhiên cho người dùng.
Đã chỉnh sửa để thêm một ví dụ về MRO mơ hồ:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Có nên Third
's MRO có [First, Second]
hay [Second, First]
? Không có kỳ vọng rõ ràng và Python sẽ phát sinh lỗi:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Chỉnh sửa: Tôi thấy một số người lập luận rằng các ví dụ ở trên thiếu super()
các cuộc gọi, vì vậy hãy để tôi giải thích: Điểm của các ví dụ là chỉ ra cách MRO được xây dựng. Họ không có ý định in "đầu tiên \ nsecond \ third" hoặc bất cứ điều gì. Tất nhiên, bạn có thể - và nên chơi xung quanh với ví dụ, thêm super()
các cuộc gọi, xem điều gì xảy ra và hiểu sâu hơn về mô hình thừa kế của Python. Nhưng mục tiêu của tôi ở đây là giữ cho nó đơn giản và chỉ ra cách MRO được xây dựng. Và nó được xây dựng như tôi đã giải thích:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
super()
được sử dụng. Tôi không khuyên bạn nên sử dụng nó với các lớp sử dụng kế thừa tuyến tính, trong đó nó chỉ là vô dụng.