Thứ năm, 13/04/2017 | 00:00 GMT+7

Cách áp dụng tính đa hình cho các lớp trong Python 3

Tính đa hình là khả năng tận dụng cùng một giao diện cho các dạng cơ bản khác nhau như kiểu dữ liệu hoặc lớp . Đ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.

Đối với lập trình hướng đối tượng trong Python, điều này nghĩa là một đối tượng cụ thể thuộc một lớp cụ thể được dùng theo cách tương tự như thể nó là một đối tượng khác thuộc một lớp khác.

Tính đa hình cho phép sự linh hoạt và khớp nối lỏng lẻo để mã có thể được mở rộng và dễ dàng duy trì theo thời gian.

Hướng dẫn này sẽ đi qua việc áp dụng tính đa hình cho các lớp trong Python.

Đa hình là gì?

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 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 overrides chúng.

Kiểu gõ vịt của Python, một trường hợp đặc biệt của kiểu gõ động, sử dụng các kỹ thuật đặc trưng của tính đa hình, bao gồm liên kết trễđiều động động . Thuật ngữ "vịt gõ" có nguồn root từ một câu nói của nhà văn James Whitcomb Riley: "Khi tôi nhìn thấy một con chim đi như vịt và bơi như vịt và bơi như vịt, tôi gọi con chim đó là vịt." Được kỹ sư máy tính người Ý Alex Martelli chiếm đoạt trong một thông điệp gửi đến group tin comp.lang.python, việc sử dụng kiểu gõ vịt liên quan đến việc cài đặt tính phù hợp của một đối tượng cho một mục đích cụ thể. Khi sử dụng cách gõ thông thường, sự phù hợp này được xác định bởi loại đối tượng, nhưng với kiểu gõ vịt, sự hiện diện của các phương thức và thuộc tính được sử dụng để xác định tính phù hợp hơn là loại thực tế của đối tượng được đề cập. Nghĩa là , bạn kiểm tra xem vật đó có chạy như vịt và đi như vịt hay không chứ không phải hỏi vật đó có phải là vịt hay không.

Khi một số lớp hoặc lớp con có tên phương thức giống nhau, nhưng cách triển khai khác nhau cho các phương thức giống nhau này, thì các lớp đó là đa hình vì chúng đang sử dụng một giao diện duy nhất để sử dụng với các thực thể thuộc các kiểu khác nhau. Một hàm sẽ có thể đánh giá các phương thức đa hình này mà không cần biết lớp nào được gọi.

Tạo các lớp đa hình

Để sử dụng tính đa hình, ta sẽ tạo hai lớp riêng biệt để sử dụng với hai đối tượng riêng biệt. Mỗi lớp riêng biệt này cần phải có một giao diện chung để chúng được dùng đa hình, vì vậy ta sẽ cung cấp cho chúng các phương thức riêng biệt nhưng có cùng tên.

Ta sẽ tạo một lớp Shark và một lớp Clownfish , mỗi lớp sẽ định nghĩa các phương thức cho swim() , swim_backwards()skeleton() .

polymorphic_fish.py
class Shark():     def swim(self):         print("The shark is swimming.")      def swim_backwards(self):         print("The shark cannot swim backwards, but can sink backwards.")      def skeleton(self):         print("The shark's skeleton is made of cartilage.")   class Clownfish():     def swim(self):         print("The clownfish is swimming.")      def swim_backwards(self):         print("The clownfish can swim backwards.")      def skeleton(self):         print("The clownfish's skeleton is made of bone.") 

Trong đoạn mã trên, cả lớp SharkClownfish đều có ba phương thức có cùng tên chung. Tuy nhiên, mỗi chức năng của các phương thức này khác nhau đối với mỗi lớp.

Hãy tạo các lớp này thành hai đối tượng:

polymorphic_fish.py
... sammy = Shark() sammy.skeleton()  casey = Clownfish() casey.skeleton() 

Khi ta chạy chương trình bằng lệnh python polymorphic_fish.py , ta có thể thấy rằng mỗi đối tượng hoạt động như mong đợi:

Output
The shark's skeleton is made of cartilage. The clownfish's skeleton is made of bone.

Bây giờ ta có hai đối tượng sử dụng một giao diện chung, ta có thể sử dụng hai đối tượng theo cách giống nhau dù loại riêng lẻ của chúng.

Đa hình với các phương thức lớp

Để hiển thị như thế nào Python có thể sử dụng mỗi người trong số các loại lớp khác nhau trong cùng một cách, đầu tiên ta có thể tạo ra một for vòng lặp đó lặp thông qua một tuple của các đối tượng. Sau đó, ta có thể gọi các phương thức mà không cần quan tâm đến loại lớp nào của mỗi đối tượng. Ta sẽ chỉ giả định các phương thức này thực sự tồn tại trong mỗi lớp.

polymorphic_fish.py
... sammy = Shark()  casey = Clownfish()  for fish in (sammy, casey):     fish.swim()     fish.swim_backwards()     fish.skeleton() 

Ta có hai đối tượng, sammy thuộc lớp Sharkcasey thuộc lớp Clownfish . Vòng lặp for của ta lặp lại qua các đối tượng này, gọi các phương thức swim() , swim_backwards()skeleton() trên mỗi đối tượng.

Khi ta chạy chương trình, kết quả kết quả sẽ như sau:

Output
The shark is swimming. The shark cannot swim backwards, but can sink backwards. The shark's skeleton is made of cartilage. The clownfish is swimming. The clownfish can swim backwards. The clownfish's skeleton is made of bone.

Vòng lặp for lặp lại đầu tiên thông qua phần tạo sammy của lớp Shark , sau đó là đối tượng casey của lớp Clownfish , vì vậy ta sẽ thấy các phương thức liên quan đến lớp Shark trước tiên, sau đó là lớp Clownfish .

Điều này cho thấy Python đang sử dụng các phương thức này theo cách mà không biết hoặc không quan tâm chính xác loại lớp của mỗi đối tượng này. Đó là, sử dụng các phương pháp này một cách đa hình.

Đa hình với một hàm

Ta cũng có thể tạo một hàm có thể lấy bất kỳ đối tượng nào, cho phép đa hình.

Hãy tạo một hàm có tên in_the_pacific() để nhận một đối tượng mà ta có thể gọi là fish . Mặc dù ta đang sử dụng tên fish , bất kỳ đối tượng được khởi tạo nào cũng có thể được gọi vào hàm này:

polymorphic_fish.py
… def in_the_pacific(fish): 

Tiếp theo, ta sẽ cung cấp cho hàm một cái gì đó để thực hiện bằng cách sử dụng đối tượng fish mà ta đã truyền cho nó. Trong trường hợp này, ta sẽ gọi các phương thức swim() , mỗi phương thức được định nghĩa trong hai lớp SharkClownfish :

polymorphic_fish.py
... def in_the_pacific(fish):     fish.swim() 

Tiếp theo, ta sẽ tạo các mô tả của cả hai lớp SharkClownfish nếu ta chưa có chúng. Với những người đó, ta có thể gọi hành động của họ bằng cách sử dụng cùng một in_the_pacific() :

polymorphic_fish.py
... def in_the_pacific(fish):     fish.swim()  sammy = Shark()  casey = Clownfish()  in_the_pacific(sammy) in_the_pacific(casey) 

Khi ta chạy chương trình, kết quả kết quả sẽ như sau:

Output
The shark is swimming. The clownfish is swimming.

Mặc dù ta đã chuyển một đối tượng ngẫu nhiên ( fish ) vào hàm in_the_pacific() khi định nghĩa nó, ta vẫn có thể sử dụng nó một cách hiệu quả cho các mô tả của các lớp SharkClownfish . Đối tượng casey được gọi là phương thức swim() được định nghĩa trong lớp Clownfish và đối tượng sammy được gọi là phương thức swim() được định nghĩa trong lớp Shark .

Kết luận

Bằng cách cho phép các đối tượng khác nhau tận dụng các hàm và phương thức theo những cách tương tự thông qua tính đa hình, việc sử dụng tính năng Python này mang lại tính linh hoạt và khả năng mở rộng cao hơn cho mã hướng đối tượng của bạn.


Tags:

Các tin liên quan

Hướng dẫn dự báo chuỗi thời gian với prophet bằng Python 3
2017-04-04
Hiểu các biến lớp và phiên bản trong Python 3
2017-03-27
Hướng dẫn Dự báo chuỗi thời gian với ARIMA bằng Python 3
2017-03-23
Cách tạo lớp và xác định đối tượng trong Python 3
2017-03-17
Hướng dẫn về image hóa chuỗi thời gian với Python 3
2017-03-14
Cách viết comment bằng Python 3
2017-03-03
Cách xác định hàm trong Python 3
2017-02-28
Phân tích và trực quan hóa dữ liệu với pandas và notebook Jupyter bằng Python 3
2017-02-23
Cách vẽ biểu đồ tần suất từ bằng matplotlib với Python 3
2017-02-17
Cách cài đặt gói pandas và làm việc với cấu trúc dữ liệu trong Python 3
2017-02-10