Hướng dẫn super() in python - siêu() trong trăn
Khi lập trình hướng đối tượng với Python, ta thường bắt gặp các câu lệnh như 0 hoặc 1 nhất là khi đọc doc của các thư viện có các lớp kế thừa nhiều lần. Bài viết hôm nay của mình sẽ hướng đến việc giới thiệu hàm 2 và các trường hợp sử dụng nó. Show 1. Kế thừa trong PythonĐể hiểu rõ hơn về vai trò của 2. Mình sẽ bắt đầu với trường hợp không sử dụng 2 trong kế thừa trước. Cho lớp cha 5 và được kế thừa bởi lớp con 6, khi đó lớp 7 có thể gọi các phương thức hoặc thuộc tính từ lớp cha.
Tuy nhiên, sẽ xảy ra trường hợp 7 và 5 có phương thức trùng tên với nhau là 0 và ta cần gọi phương thức 0 của 5 bên trong phương thức 3 của 7. Trường hợp này vẫn có thể được giải quyết mà không cần dùng đến 2 bằng cách gọi trực tiếp 6 bên trong 7
Chúng ta cũng có thể giải quyết trường hợp này bằng 2 thay vì gọi trực tiếp
Hàm 2 lúc này sẽ trả về một đối tượng thuộc lớp kế thừa từ 7 lúc này là 5 và gọi 5. Khác với cách gọi trực tiếp, 2 không cần viết lại tên lớp 5 khi gọi hàm, việc này sẽ giúp tránh bị các lỗi chính tả hoặc bạn có nhu cầu đổi tên lớp cha hoặc kế thừa từ lớp khác. Nhưng đấy vẫn chưa phải là tất cả điểm mạnh của 2. 2 được sử dụng linh hoạt trong các trường hợp đa kế thừa đặc biệt là Diamond Problem mà mình sẽ giới thiệu sau đây. Trước tiên chúng ta cần phải hiểu rõ một vài khái niệm và các tham số của 2Nhưng đấy vẫn chưa phải là tất cả điểm mạnh của 2. 2 được sử dụng linh hoạt trong các trường hợp đa kế thừa đặc biệt là Diamond Problem mà mình sẽ giới thiệu sau đây. Trước tiên
chúng ta cần phải hiểu rõ một vài khái niệm và các tham số của 22. Method resolution order (MRO)MRO có thể hiểu đơn giản là trình tự kế thừa của lớp. MRO của một lớp có thể được truy xuất bằng phương thức 1 MRO sẽ được tạo để đảm bảo các lớp chỉ được liệt kê một lần và các lớp con phải được gọi trước lớp cha. Nếu bạn muốn tìm hiểu thêm về thuật toán tạo MRO của Python thì tham khảo tại đâyMRO sẽ được tạo để đảm bảo các lớp chỉ được liệt kê một lần và các lớp con phải được gọi trước lớp cha. Nếu bạn muốn tìm hiểu thêm về thuật toán tạo MRO của Python thì tham khảo tại đây
Khi sử dụng một phương thức với đối tượng thuộc lớp Children, chương trình sẽ tìm kiếm phương thức dựa trên thứ tự MRO như trên, tức là bắt đầu từ Children, nếu không có thì sẽ tìm đến Parent và sau cùng là object (base class mặc định cho mọi loại dữ liệu Python) 3. Tham số của hàm super()Hàm 2 sẽ nhận vào hai tham số 3 và 4:
Để dễ hình dung, 0 có thể hiểu là 1 với phương thức 2 được cài đặt trong lớp cha của 3.Xét ví dụ trên, hàm 2 được gọi trong lớp 7 sẽ có giá trị tham số mặc định là 6. Ngoài ra 3 và 4 còn có một số ràng buộc để chương trình chạy không bị lỗi mà bạn có thể tham khảo tại doc của 2
4. Giải quyết Diamond Problem bằng super()Diamond Problem xuất hiện khi ta thực hiện đa kế thừa trên hai lớp cha cùng kế thừa từ một lớp ông nội. Xét trường hợp ta có các lớp sau: Xét trường hợp ta có các lớp sau:
Khi đó chúng ta sẽ gặp các vấn đề phát sinh sau:
Nếu bạn gọi phương thức bằng 2, phương thức của lớp có thứ tự nhỏ hơn trong MRO sẽ được gọi trước. Trong trường hợp này, thứ tự lớp cha trong MRO sẽ là thứ tự liệt kê lớp cha trong lúc khai báo lớp 7.
Nếu muốn gọi 0 của 5 ta có thể làm như sau:
Phương thức của lớp Vấn đề này gặp khi chúng ta muốn gọi phương thức khởi tạo của 4 và 5 trực tiếp bên trong 7, nhưng phương thức khởi tạo của 4 và 5 lại gọi phương thức khởi tạo của 2. Khi đó sẽ xảy ra việc phương thức khởi tạo của 2 bị gọi 2 lần.
Cách giải quyết: sử dụng hàm 2 thay vì gọi trực tiếp. Như đã lưu ý ở mục 3. hàm 2 sẽ tìm các phương thức khởi tạo dựa trên MRO và lớp hiện tại. Vì các
lớp chỉ xuất hiện trong MRO duy nhất một lần nên khi gọi 0 sẽ tránh được việc gọi nhiều lần, giảm thiểu thời gian chạy và tránh bị ghi đè không cần thiết.
Tuy nhiên cách này lại dẫn đến vấn đề sau Phương thức khởi tạo của 7, 8, 9 và 00Xét đoạn code sau đây:
Mỗi lớp đều cần một tham số khác nhau khi khởi tạo nên theo thứ tự MRO biết trước, chúng ta có thể viết code như trên. Tuy code chạy đúng như ý muốn nhưng mình tin chẳng ai muốn code như trên vì các lí do sau:
Cách giải quyết: sử dụng 13 trong 06. Khi đó chúng ta cần phải thiết kế lại tất cả các phương thức 06 của tất cả các lớp:
Code vẫn trả về kết quả như ý nhưng gọn hơn và dễ bảo trì, mở rộng hơn! Chúng ta vẫn có thể giải quyết trường hợp này bằng cách gọi phương thức khởi tạo trực tiếp nếu bạn đảm bảo không bị ghi đè cho lớp 1 hoặc việc ghi đè không gây ảnh hưởng gì (nhưng mình vẫn khuyến khích sử dụng 2 hơn vì lí do bảo trì và mở rộng!)5. Kết bàiQua bài này mình đã trình bày với các bạn:
Nếu bài viết có chỗ nào không rõ hoặc sai thì xin hãy cho mình biết. Cảm ơn các bạn đã dành thời gian đọc bài viết này! 6. Tham khảo
|