Thừa kế và Đa hình
Tính kế thừa và tính đa hình - đây là một khái niệm rất quan trọng trong Python. Bạn phải hiểu nó tốt hơn nếu bạn muốn học.
Di sản
Một trong những ưu điểm chính của Lập trình hướng đối tượng là khả năng tái sử dụng. Kế thừa là một trong những cơ chế để đạt được điều tương tự. Tính kế thừa cho phép lập trình viên tạo ra một lớp tổng quát hoặc một lớp cơ sở đầu tiên và sau đó mở rộng nó sang lớp chuyên biệt hơn. Nó cho phép lập trình viên viết mã tốt hơn.
Sử dụng kế thừa, bạn có thể sử dụng hoặc kế thừa tất cả các trường dữ liệu và phương thức có sẵn trong lớp cơ sở của bạn. Sau đó, bạn có thể thêm các phương thức và trường dữ liệu của riêng mình, do đó, kế thừa cung cấp một cách để tổ chức mã, thay vì viết lại từ đầu.
Trong thuật ngữ hướng đối tượng khi lớp X mở rộng lớp Y, thì Y được gọi là lớp siêu / cha / cơ sở và X được gọi là lớp con / lớp con / lớp dẫn xuất. Một điểm cần lưu ý ở đây là chỉ các trường dữ liệu và phương thức không riêng tư mới có thể truy cập được bởi các lớp con. Các trường và phương thức dữ liệu riêng tư chỉ có thể truy cập được bên trong lớp.
cú pháp để tạo một lớp dẫn xuất là:
class BaseClass:
Body of base class
class DerivedClass(BaseClass):
Body of derived class
Kế thừa các thuộc tính
Bây giờ hãy xem ví dụ dưới đây -
Đầu ra
Đầu tiên chúng ta tạo một lớp có tên là Date và truyền đối tượng làm đối số, đối tượng ở đây là lớp tích hợp do Python cung cấp. Sau đó, chúng tôi tạo một lớp khác được gọi là thời gian và gọi lớp Ngày như một đối số. Thông qua cuộc gọi này, chúng ta có quyền truy cập vào tất cả dữ liệu và thuộc tính của lớp Ngày vào lớp Thời gian. Vì điều đó khi chúng ta cố gắng lấy phương thức get_date từ đối tượng lớp Thời gian tm mà chúng ta đã tạo trước đó.
Cấu trúc phân cấp tra cứu đối tượng.
- Ví dụ
- Lớp
- Bất kỳ lớp nào mà lớp này kế thừa
Ví dụ về thừa kế
Hãy cùng xem xét ví dụ về kế thừa -
Hãy tạo vài lớp để tham gia vào các ví dụ -
- Động vật - Lớp mô phỏng một con vật
- Mèo - Phân lớp động vật
- Chó - Phân lớp động vật
Trong Python, hàm tạo của lớp được sử dụng để tạo một đối tượng (cá thể) và gán giá trị cho các thuộc tính.
Hàm tạo của lớp con luôn được gọi tới hàm tạo của lớp cha để khởi tạo giá trị cho các thuộc tính trong lớp cha, sau đó nó bắt đầu gán giá trị cho các thuộc tính của nó.
Đầu ra
Trong ví dụ trên, chúng ta thấy các thuộc tính lệnh hoặc phương thức chúng ta đặt trong lớp cha để tất cả các lớp con hoặc lớp con sẽ kế thừa thuộc tính đó từ lớp cha.
Nếu một lớp con cố gắng kế thừa các phương thức hoặc dữ liệu từ một lớp con khác thì nó sẽ xảy ra lỗi như chúng ta thấy khi lớp Dog cố gắng gọi các phương thức swatstring () từ lớp cat đó, nó sẽ tạo ra một lỗi (như AttributeError trong trường hợp của chúng ta).
Đa hình (“NHIỀU HÌNH DẠNG”)
Tính đa hình là một tính năng quan trọng của định nghĩa lớp trong Python được sử dụng khi bạn có các phương thức thường được đặt tên trên các lớp hoặc lớp con. Điều này cho phép các chức năng sử dụng các thực thể thuộc các loại khác nhau tại các thời điểm khác nhau. Vì vậy, nó cung cấp tính linh hoạt và khớp nối lỏng lẻo để mã có thể được mở rộng và dễ dàng bảo trì theo thời gian.
Điều này cho phép các hàm sử dụng các đối tượng của bất kỳ lớp đa hình nào mà không cần biết đến sự khác biệt giữa các lớp.
Đa hình có thể được thực hiện thông qua kế thừa, với các lớp con sử dụng các phương thức của lớp cơ sở hoặc ghi đè chúng.
Hãy hiểu khái niệm đa hình với ví dụ kế thừa trước của chúng tôi và thêm một phương thức chung gọi là show_affection trong cả hai lớp con -
Từ ví dụ chúng ta có thể thấy, nó đề cập đến một thiết kế trong đó đối tượng của kiểu khác nhau có thể được xử lý theo cùng một cách hoặc cụ thể hơn là hai hoặc nhiều lớp có phương thức cùng tên hoặc giao diện chung vì cùng một phương thức (show_affection trong ví dụ bên dưới) được gọi với một trong hai loại đối tượng.
Đầu ra
Vì vậy, tất cả các loài động vật đều thể hiện tình cảm (show_affection), nhưng chúng lại làm khác đi. Do đó, các hành vi “show_affection” là đa hình theo nghĩa là nó hoạt động khác nhau tùy thuộc vào con vật. Vì vậy, khái niệm trừu tượng “động vật” không thực sự là “show_affection”, nhưng các động vật cụ thể (như chó và mèo) có một triển khai cụ thể của hành động “show_affection”.
Bản thân Python có các lớp là đa hình. Ví dụ, hàm len () có thể được sử dụng với nhiều đối tượng và tất cả đều trả về đầu ra chính xác dựa trên tham số đầu vào.
Ghi đè
Trong Python, khi một lớp con chứa một phương thức ghi đè một phương thức của lớp cha, bạn cũng có thể gọi phương thức lớp cha bằng cách gọi
Siêu (Lớp con, tự) .method thay vì self.method.
Thí dụ
class Thought(object):
def __init__(self):
pass
def message(self):
print("Thought, always come and go")
class Advice(Thought):
def __init__(self):
super(Advice, self).__init__()
def message(self):
print('Warning: Risk is always involved when you are dealing with market!')
Kế thừa hàm tạo
Nếu chúng ta thấy từ ví dụ kế thừa trước đó của mình, __init__ được đặt trong lớp cha ở trên vì con chó hoặc con mèo của lớp con không có phương thức __init__ trong đó. Python đã sử dụng tra cứu thuộc tính kế thừa để tìm __init__ trong lớp động vật. Khi chúng ta tạo lớp con, đầu tiên nó sẽ tìm phương thức __init__ trong lớp dog, sau đó nó không tìm thấy nó, sau đó tìm vào lớp cha Animal và tìm thấy ở đó và gọi phương thức đó ở đó. Vì vậy, khi thiết kế lớp của chúng ta trở nên phức tạp, chúng ta có thể muốn khởi tạo một thể hiện trước tiên xử lý nó thông qua phương thức khởi tạo lớp cha và sau đó thông qua phương thức khởi tạo lớp con.
Đầu ra
Trong ví dụ trên - tất cả các loài động vật đều có một cái tên và tất cả các con chó là một giống cụ thể. Chúng tôi đã gọi hàm tạo lớp cha với super. Vì vậy, con chó có __init__ của riêng nó nhưng điều đầu tiên xảy ra là chúng tôi gọi là siêu. Super được xây dựng trong hàm và nó được thiết kế để liên kết một lớp với siêu lớp hoặc lớp cha của nó.
Trong trường hợp này, chúng ta nói rằng lấy super class của dog và truyền instance dog vào bất kỳ phương thức nào mà chúng ta nói ở đây là constructor __init__. Vì vậy, nói cách khác, chúng ta đang gọi lớp cha là Animal __init__ với đối tượng dog. Bạn có thể hỏi tại sao chúng tôi không chỉ nói Animal __init__ với trường hợp chó, chúng tôi có thể làm điều này nhưng nếu tên của lớp động vật được thay đổi, đôi khi trong tương lai. Điều gì sẽ xảy ra nếu chúng ta muốn sắp xếp lại hệ thống phân cấp lớp, để con chó được thừa kế từ một lớp khác. Sử dụng super trong trường hợp này cho phép chúng ta giữ mọi thứ theo mô-đun và dễ dàng thay đổi và bảo trì.
Vì vậy, trong ví dụ này, chúng tôi có thể kết hợp chức năng __init__ chung với chức năng cụ thể hơn. Điều này cho chúng ta cơ hội để tách chức năng chung khỏi chức năng cụ thể, có thể loại bỏ sự trùng lặp mã và liên kết lớp với nhau theo cách phản ánh thiết kế tổng thể của hệ thống.
Phần kết luận
__init__ giống như bất kỳ phương thức nào khác; nó có thể được kế thừa
Nếu một lớp không có phương thức khởi tạo __init__, Python sẽ kiểm tra lớp cha của nó để xem liệu nó có thể tìm thấy một hàm không.
Ngay sau khi nó tìm thấy một cái, Python sẽ gọi nó và ngừng tìm kiếm
Chúng ta có thể sử dụng hàm super () để gọi các phương thức trong lớp cha.
Chúng ta có thể muốn khởi tạo trong lớp cha cũng như lớp của chúng ta.
Nhiều tài sản thừa kế và cây tra cứu
Như tên của nó đã chỉ ra, đa kế thừa là Python là khi một lớp kế thừa từ nhiều lớp.
Ví dụ, một đứa trẻ thừa hưởng các đặc điểm tính cách từ cả cha lẫn mẹ (Cha và mẹ).
Cú pháp kế thừa nhiều trong Python
Để tạo một lớp kế thừa từ nhiều lớp cha, chúng ta viết tên của các lớp này bên trong dấu ngoặc đơn cho lớp dẫn xuất trong khi định nghĩa nó. Chúng tôi phân tách các tên này bằng dấu phẩy.
Dưới đây là một ví dụ về điều đó -
>>> class Mother:
pass
>>> class Father:
pass
>>> class Child(Mother, Father):
pass
>>> issubclass(Child, Mother) and issubclass(Child, Father)
True
Đa kế thừa đề cập đến khả năng kế thừa từ hai hoặc nhiều hơn hai lớp. Sự phức tạp nảy sinh khi con kế thừa từ lớp cha mẹ và cha mẹ kế thừa từ lớp ông bà. Python trèo lên một cây kế thừa để tìm kiếm các thuộc tính đang được yêu cầu đọc từ một đối tượng. Nó sẽ kiểm tra cá thể trong trường hợp, trong lớp rồi đến lớp cha và cuối cùng là từ lớp ông bà. Bây giờ câu hỏi được đặt ra theo thứ tự các lớp sẽ được tìm kiếm - tìm kiếm trước hay theo chiều sâu. Theo mặc định, Python đi với độ sâu đầu tiên.
Đó là lý do tại sao trong sơ đồ dưới đây, Python tìm kiếm phương thức dothis () đầu tiên trong lớp A. Vì vậy, thứ tự phân giải phương thức trong ví dụ dưới đây sẽ là
Mro- D→B→A→C
Nhìn vào sơ đồ đa kế thừa bên dưới -
Hãy xem qua một ví dụ để hiểu tính năng “mro” của Python.
Đầu ra
Ví dụ 3
Hãy lấy một ví dụ khác về đa thừa kế "hình thoi".
Sơ đồ trên sẽ được coi là mơ hồ. Từ ví dụ trước của chúng ta hiểu “thứ tự phân giải phương pháp” .ie mro sẽ là D → B → A → C → A nhưng không phải vậy. Khi lấy A thứ hai từ C, Python sẽ bỏ qua A. trước đó, vì vậy mro sẽ ở trong trường hợp này sẽ là D → B → C → A.
Hãy tạo một ví dụ dựa trên sơ đồ trên -
Đầu ra
Quy tắc đơn giản để hiểu kết quả đầu ra ở trên là- nếu cùng một lớp xuất hiện theo thứ tự phân giải phương thức, các lần xuất hiện trước đó của lớp này sẽ bị xóa khỏi thứ tự phân giải phương thức.
Kết luận -
Bất kỳ lớp nào cũng có thể kế thừa từ nhiều lớp
Python thường sử dụng thứ tự “chiều sâu” khi tìm kiếm các lớp kế thừa.
Nhưng khi hai lớp kế thừa từ cùng một lớp, Python sẽ loại bỏ các lần xuất hiện đầu tiên của lớp đó khỏi mro.
Trình trang trí, Phương thức tĩnh và Lớp
Các hàm (hoặc phương thức) được tạo bởi câu lệnh def.
Mặc dù các phương thức hoạt động giống hệt như một hàm ngoại trừ một điểm mà đối số đầu tiên của phương thức là đối tượng thể hiện.
Chúng tôi có thể phân loại các phương pháp dựa trên cách chúng hoạt động, như
Simple method- được định nghĩa bên ngoài một lớp. Hàm này có thể truy cập các thuộc tính của lớp bằng cách cấp đối số phiên bản:
def outside_func(():
Instance method -
def func(self,)
Class method - nếu chúng ta cần sử dụng thuộc tính lớp
@classmethod
def cfunc(cls,)
Static method - không có bất kỳ thông tin nào về lớp học
@staticmethod
def sfoo()
Cho đến bây giờ chúng ta đã thấy phương thức instance, bây giờ là lúc để tìm hiểu sâu hơn về hai phương thức còn lại,
Phương pháp lớp học
@Classmethod decorator, là một trình trang trí hàm dựng sẵn được chuyển vào lớp mà nó được gọi hoặc lớp của cá thể mà nó được gọi làm đối số đầu tiên. Kết quả của đánh giá đó làm mờ định nghĩa chức năng của bạn.
cú pháp
class C(object):
@classmethod
def fun(cls, arg1, arg2, ...):
....
fun: function that needs to be converted into a class method
returns: a class method for function
Họ có quyền truy cập vào đối số cls này, nó không thể sửa đổi trạng thái cá thể đối tượng. Điều đó sẽ yêu cầu quyền truy cập vào bản thân.
Nó bị ràng buộc với lớp chứ không phải đối tượng của lớp.
Các phương thức lớp vẫn có thể sửa đổi trạng thái lớp áp dụng cho tất cả các trường hợp của lớp.
Phương pháp tĩnh
Một phương thức tĩnh không nhận tham số self hay cls (class) nhưng có thể chấp nhận một số lượng tùy ý các tham số khác.
syntax
class C(object):
@staticmethod
def fun(arg1, arg2, ...):
...
returns: a static method for function funself.
- Một phương thức tĩnh không thể sửa đổi trạng thái đối tượng cũng như trạng thái lớp.
- Họ bị hạn chế về dữ liệu họ có thể truy cập.
Khi nào dùng cái gì
Chúng tôi thường sử dụng phương thức lớp để tạo các phương thức nhà máy. Các phương thức nhà máy trả về đối tượng lớp (tương tự như một phương thức khởi tạo) cho các trường hợp sử dụng khác nhau.
Chúng tôi thường sử dụng các phương thức tĩnh để tạo các hàm tiện ích.