Đa hình trong Python

Category: Python

Đa hình là một khái niệm cơ bản trong lập trình cho phép các thực thể như hàm, phương thức hoặc toán tử hoạt động khác nhau dựa trên loại dữ liệu mà chúng đang xử lý. Có nguồn gốc từ tiếng Hy Lạp, thuật ngữ này theo nghĩa đen có nghĩa là "nhiều dạng".

Kiểu động và kiểu vịt của Python khiến nó có tính đa hình. Các hàm, toán tử và thậm chí các đối tượng tích hợp như vòng lặp đều thể hiện hành vi đa hình.

Đa hình trong các hàm dựng sẵn

Các hàm dựng sẵn của Python thể hiện tính đa hình, thích ứng với nhiều kiểu dữ liệu khác nhau.

Ví dụ:

print(len("Hello"))  # Chiều dài chuỗi
print(len([1, 2, 3]))  # Độ dài danh sách

print(max(1, 3, 2))  # Số nguyên tối đa
print(max("a", "z", "m"))  # Tối đa trong chuỗi

Python xác định hành vi khi chạy, cho phép các hàm này hoạt động trên nhiều kiểu dữ liệu khác nhau mà không cần khai báo kiểu rõ ràng.

Chúng ta hãy cùng tìm hiểu chi tiết về đa hình:

Mục lục

  • Đa hình trong các hàm dựng sẵn

  • Đa hình trong hàm

  • Đa hình trong các toán tử

  • Đa hình trong lập trình hướng đối tượng (OOP)

  • Các loại đa hình

  • Đa hình lớp kế thừa

Đa hình trong hàm

Kiểu Duck cho phép các hàm hoạt động với bất kỳ đối tượng nào bất kể loại của nó.
Ví dụ:

def add(a, b):
    return a + b

print(add(3, 4))           # Phép cộng số nguyên
print(add("Hello, ", "World!"))  # Nối chuỗi
print(add([1, 2], [3, 4])) # Nối danh sách

Đa hình trong các toán tử

Quá tải toán tử

Trong Python, các toán tử như + hoạt động theo kiểu đa hình, thực hiện phép cộng, nối hoặc hợp nhất dựa trên kiểu dữ liệu .

Ví dụ:

print(5 + 10)  # Cộng số nguyên
print("Hello " + "World!")  # Nối chuỗi
print([1, 2] + [3, 4])  # Nối danh sách

Đa hình trong OOP

Trong OOP , đa hình cho phép các phương thức trong các lớp khác nhau chia sẻ cùng một tên nhưng thực hiện các tác vụ riêng biệt. Điều này đạt được thông qua kế thừa và thiết kế giao diện. Đa hình bổ sung cho các nguyên tắc OOP khác như kế thừa (chia sẻ hành vi) và đóng gói (ẩn độ phức tạp) để tạo ra các ứng dụng mạnh mẽ và có tính mô-đun.

Ví dụ:

class Shape:
    def area(self):
        return "Undefined"

class Rectangle(Shape):
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

shapes = [Rectangle(2, 3), Circle(5)]
for shape in shapes:
    print(f"Area: {shape.area()}")

Giải thích:

  • Mã này thể hiện tính đa hình bằng cách sử dụng lớp cha Shape và các lớp con Rectangle và Circle.

  • Lớp cha Shape: Chứa phương thức vùng chung trả về "Undefined", đóng vai trò là chỗ giữ chỗ để các lớp con ghi đè.

  • Lớp con Rectangle: Khởi tạo chiều dài và chiều rộng thông qua hàm tạo init. Ghi đè phương thức area để trả về diện tích của hình chữ nhật dưới dạng chiều dài * chiều rộng.

  • Lớp con Circle: Khởi tạo bán kính thông qua hàm tạo init. Ghi đè phương thức area để trả về diện tích hình tròn là 3,14 * radius^2.

  • Hành vi đa hình: Một danh sách các đối tượng hình dạng (Hình chữ nhật và Hình tròn) được tạo ra. Một vòng lặp for lặp qua danh sách, gọi phương thức area trên mỗi đối tượng. Phương thức được thực thi được xác định bởi loại đối tượng, thể hiện tính đa hình.

Các loại đa hình

Đa hình thời gian biên dịch

  • Được tìm thấy trong các ngôn ngữ có kiểu tĩnh như Java hoặc C++, trong đó hành vi của hàm hoặc toán tử được giải quyết trong giai đoạn biên dịch chương trình.

  • Các ví dụ bao gồm quá tải phương thức và quá tải toán tử, trong đó nhiều hàm hoặc toán tử có thể dùng chung tên nhưng thực hiện các tác vụ khác nhau tùy theo ngữ cảnh.

  • Trong Python, được gõ động, đa hình thời gian biên dịch không được hỗ trợ gốc. Thay vào đó, Python sử dụng các kỹ thuật như gõ động và gõ vịt để đạt được tính linh hoạt tương tự.

Đa hình thời gian chạy

  • Xảy ra khi hành vi của một phương thức được xác định tại thời gian chạy dựa trên loại đối tượng.

  • Trong Python, điều này đạt được thông qua việc ghi đè phương thức : lớp con có thể định nghĩa lại phương thức từ lớp cha để cung cấp triển khai cụ thể của riêng nó.

  • Bản chất động của Python cho phép nó vượt trội về đa hình thời gian chạy, tạo ra mã linh hoạt và dễ thích ứng.

Ví dụ:

class Animal:
    def sound(self):
        return "Some generic sound"

class Dog(Animal):
    def sound(self):
        return "Bark"

class Cat(Animal):
    def sound(self):
        return "Meow"

# Hành vi đa hình
animals = [Dog(), Cat(), Animal()]
for animal in animals:
    print(animal.sound())  # Gọi phương thức ghi đè dựa trên loại đối tượng

Đầu ra:

Bark
Meow
Some generic sound

Giải thích: Ở đây, phương thức âm thanh hoạt động khác nhau tùy thuộc vào việc đối tượng là Chó, Mèo hay Động vật và quyết định này xảy ra khi chạy. Bản chất động này làm cho Python đặc biệt mạnh mẽ cho đa hình thời gian chạy.

Đa hình lớp kế thừa

Đa hình dựa trên kế thừa xảy ra khi một lớp con ghi đè một phương thức từ lớp cha của nó, cung cấp một triển khai cụ thể. Quá trình triển khai lại một phương thức trong lớp con này được gọi là Ghi đè phương thức .  

Ví dụ:

class Animal:
    def sound(self):
        return "Some generic animal sound"

class Dog(Animal):
    def sound(self):
        return "Bark"

class Cat(Animal):
    def sound(self):
        return "Meow

Giải thích:

  • Lớp Animal: Hoạt động như lớp cơ sở (cha). Chứa phương thức sound cung cấp hành vi mặc định, trả về "Some generic animal sound". Đây là biểu diễn chung của phương thức sound cho tất cả các loài động vật.

  • Lớp Dog: Kế thừa từ lớp Animal (được biểu thị bằng lớp Dog(Animal)). Ghi đè phương thức sound để trả về "Bark", một hành vi dành riêng cho chó. Điều này chứng minh phương thức ghi đè, trong đó lớp con sửa đổi việc triển khai phương thức của lớp cha.

  • Lớp Cat: Kế thừa từ lớp Animal (được biểu thị bằng lớp Cat(Animal)). Ghi đè phương thức âm thanh để trả về "Meow", một hành vi dành riêng cho mèo. Giống như Dog, điều này cũng chứng minh phương thức ghi đè.

Published on Jun 19, 2025