Series học Python từ A tới Á - 2
9 min read

Series học Python từ A tới Á - 2

Phần tiếp theo

Trong phần trước, mình đã lược qua những khái niệm cơ bản nhất của ngôn ngữ lập trình Python: Variable, Condition Statement, Looping, Iterate. Ở phần này, chúng ta sẽ tìm hiểu về Lập trình Hướng đối tượng OOP và Lập trình Hàm FP trong Python.

Nói qua về Hướng đối tượng, Python là 1 ngôn ngữ thuần 100% Hướng đối tượng, nghĩa là tất cả các thành phần trong Python đều là đối tượng. Ngoài ra nó còn hỗ trợ các khái niệm Lập trình Hàm hoàn chỉnh. Chúng ta hãy cũng đi qua những khái niệm này nhé.

Object-Oriented Programming

Lập trình hướng đối tượng (OOP) là một phương pháp lập trình dựa trên khái niệm đối tượng. Một đối tượng là một thực thể có trạng thái và hành vi. Trạng thái của một đối tượng được lưu trữ trong các thuộc tính của nó, còn hành vi của nó được xác định bởi các phương thức của nó.

Trong Python, mọi thứ đều là một đối tượng, bao gồm các số nguyên, chuỗi, danh sách, v.v. Điều này có nghĩa là các khái niệm của OOP có thể được áp dụng cho tất cả các loại dữ liệu.

Các khái niệm chính của OOP trong Python bao gồm:

  • Lớp: Một lớp là một định nghĩa cho một loại đối tượng. Nó xác định các thuộc tính và phương thức của đối tượng.
  • Tạo đối tượng: Một đối tượng được tạo bằng cách khởi tạo một lớp.
  • Thuộc tính: Một thuộc tính là một biến liên kết với một đối tượng. Nó có thể được sử dụng để lưu trữ dữ liệu về đối tượng.
  • Phương thức: Một phương thức là một hàm liên kết với một đối tượng. Nó có thể được sử dụng để thực hiện các hành động trên đối tượng.
  • Kế thừa: Kế thừa là khả năng một lớp kế thừa các thuộc tính và phương thức từ một lớp khác.
  • Đa hình: Đa hình là khả năng của một đối tượng để thể hiện nhiều loại khác nhau.

OOP có nhiều lợi ích, bao gồm:

  • Đóng gói: OOP giúp đóng gói dữ liệu và mã liên quan với nhau thành một đơn vị duy nhất. Điều này giúp tăng cường bảo mật và khả năng bảo trì.
  • Tái sử dụng: OOP giúp tái sử dụng mã bằng cách cho phép các lớp kế thừa từ các lớp khác.
  • Tính trừu tượng: OOP giúp trừu tượng hóa các chi tiết thực thi khỏi giao diện của một đối tượng. Điều này giúp tăng cường khả năng mở rộng và bảo trì.

OOP là một kỹ thuật lập trình mạnh mẽ có thể được sử dụng để tạo các ứng dụng phức tạp và linh hoạt.

Đối tượng và Lớp

Object và class là hai khái niệm quan trọng trong lập trình hướng đối tượng (OOP) của Python.

Object là một thực thể có trạng thái và hành vi. Trạng thái của một object được lưu trữ trong các thuộc tính của nó, còn hành vi của nó được xác định bởi các phương thức của nó.

Class là một định nghĩa cho một loại object. Nó xác định các thuộc tính và phương thức của object.

Để tạo một object, bạn cần sử dụng từ khóa class để khai báo một lớp, sau đó sử dụng từ khóa () để khởi tạo một object mới. Ví dụ, đoạn code sau sẽ tạo một lớp Student với các thuộc tính nameage:

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

Đoạn code sau sẽ tạo một object mới từ lớp Student:

student = Student("John Doe", 20)

Object có thể truy cập các thuộc tính và gọi các phương thức của nó bằng cách sử dụng dấu chấm (.).

Ví dụ, đoạn code sau sẽ truy cập thuộc tính name của object student:

print(student.name)

Đoạn code sau sẽ gọi phương thức greet() của object student:

student.greet()

OOP cung cấp nhiều lợi ích cho lập trình viên, bao gồm:

  • Đóng gói: OOP giúp đóng gói dữ liệu và mã liên quan với nhau thành một đơn vị duy nhất. Điều này giúp tăng cường bảo mật và khả năng bảo trì.
  • Tái sử dụng: OOP giúp tái sử dụng mã bằng cách cho phép các lớp kế thừa từ các lớp khác.
  • Tính trừu tượng: OOP giúp trừu tượng hóa các chi tiết thực thi khỏi giao diện của một object. Điều này giúp tăng cường khả năng mở rộng và bảo trì.

OOP là một kỹ thuật lập trình mạnh mẽ có thể được sử dụng để tạo các ứng dụng phức tạp và linh hoạt.

Phương thức Getter Setter & Decorator

Trong Python, getter và setter là các phương thức được sử dụng để truy cập và thay đổi một thuộc tính của một đối tượng. Getter được sử dụng để truy cập giá trị của một thuộc tính, còn setter được sử dụng để thay đổi giá trị của một thuộc tính.

Có hai cách để tạo getter và setter trong Python:

  • Sử dụng hàm property()
  • Sử dụng decorator @property

Cả hai cách đều cho phép tạo getter và setter, nhưng sử dụng decorator @property thường được coi là cách viết code Pythonic hơn.

Decorator @property là một cách đơn giản và ngắn gọn để tạo getter và setter. Ví dụ:

class Student:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, new_name):
        self._name = new_name

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, new_age):
        if new_age < 18:
            raise ValueError("Age must be greater than 18")
        self._age = new_age

Trong đoạn code trên, hàm name()age() là các getter và setter được tạo bằng cách sử dụng decorator @property.

Getter và setter được sử dụng để đóng gói dữ liệu, giúp bảo vệ dữ liệu khỏi bị thay đổi một cách không mong muốn. Ngoài ra, getter và setter cũng có thể được sử dụng để thêm logic cho việc truy cập và thay đổi dữ liệu.

Tính Bao đóng (Encapsulation)

Tính bao đóng (encapsulation) là một trong những tính chất quan trọng của lập trình hướng đối tượng (OOP). Trong Python, tính bao đóng được thể hiện thông qua các thuộc tính và phương thức của một lớp.

Các thuộc tính và phương thức của một lớp có thể được chia thành hai loại:

  • Public: Các thuộc tính và phương thức public có thể được truy cập từ bên ngoài lớp.
  • Private: Các thuộc tính và phương thức private chỉ có thể được truy cập từ bên trong lớp.

Tính bao đóng giúp bảo vệ dữ liệu và logic của một lớp khỏi bị truy cập hoặc thay đổi một cách không mong muốn. Điều này giúp cho mã nguồn trở nên an toàn và dễ bảo trì hơn.

Ví dụ, trong đoạn code sau:

class Student:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def get_name(self):
        return self._name

    def set_name(self, new_name):
        self._name = new_name

    def get_age(self):
        return self._age

    def set_age(self, new_age):
        if new_age < 18:
            raise ValueError("Age must be greater than 18")
        self._age = new_age

Tất cả các thuộc tính và phương thức của lớp Student đều là private, ngoại trừ các phương thức getter và setter cho hai thuộc tính nameage. Điều này có nghĩa là các thuộc tính nameage chỉ có thể được truy cập hoặc thay đổi thông qua các phương thức getter và setter.

Việc sử dụng tính bao đóng trong Python giúp cho mã nguồn của lớp Student trở nên an toàn hơn. Ví dụ, nếu một đối tượng Student được tạo ra và gán cho nó một giá trị age nhỏ hơn 18, thì giá trị này sẽ không thể được thay đổi trực tiếp thông qua thuộc tính age. Thay vào đó, cần phải sử dụng phương thức set_age() để thay đổi giá trị của age. Điều này giúp ngăn chặn việc một đối tượng Student có tuổi nhỏ hơn 18 được tạo ra.

Tính Thừa kế (Inheritance)


Tính thừa kế trong Python không chỉ giúp tạo ra mối quan hệ giữa các lớp và tái sử dụng mã nguồn, mà còn là một cơ chế mạnh mẽ giúp tạo nên cấu trúc tổ chức hợp lý cho mã nguồn. Lớp con kế thừa tất cả các thuộc tính và phương thức của lớp cha, nhưng cũng có thể thêm vào, ghi đè hoặc thay đổi các thuộc tính và phương thức đó. Python hỗ trợ đa thừa kế, cho phép một lớp kế thừa từ nhiều lớp cha.

Ví dụ, giả sử chúng ta đang xây dựng một ứng dụng quản lý động vật. Chúng ta có thể tạo ra một lớp cơ bản tên là 'ĐộngVật' với các thuộc tính và phương thức chung như 'tên', 'tuổi', 'tiếng kêu', v.v.

Sau đó, chúng ta có thể tạo ra các lớp con như 'Mèo', 'Chó' kế thừa từ lớp 'ĐộngVật' và thêm vào các thuộc tính và phương thức đặc trưng riêng, như 'số màu lông' cho 'Mèo', hoặc 'kích thước đuôi' cho 'Chó'.

class DongVat:
    def __init__(self, ten, tuoi):
        self.ten = ten
        self.tuoi = tuoi

    def tieng_keu(self):
        pass

class Meo(DongVat):
    def __init__(self, ten, tuoi, so_mau_long):
        super().__init__(ten, tuoi)
        self.so_mau_long = so_mau_long

    def tieng_keu(self):
        return 'Meo meo'

class Cho(DongVat):
    def __init__(self, ten, tuoi, kich_thuoc_duoi):
        super().__init__(ten, tuoi)
        self.kich_thuoc_duoi = kich_thuoc_duoi

    def tieng_keu(self):
        return 'Gau gau'

# Sử dụng
micky = Cho('Micky', 5, 'Dài')
print(micky.ten) # Output: Micky
print(micky.tieng_keu()) # Output: Gau gau

Ở đây, 'Meo' và 'Cho' là các lớp con của 'DongVat' và mỗi lớp con đều có các phương thức và thuộc tính riêng, cũng như ghi đè phương thức 'tieng_keu' của lớp cha.

Tính Đa hình (Polymorphism)

Tính đa hình (polymorphism) trong Python là khả năng của một đối tượng có thể nhận nhiều hình thức. Điều này có nghĩa là một lớp con có thể thực hiện các hành động giống như một lớp cha, cho phép sử dụng đối tượng của lớp con như một đối tượng của lớp cha, làm cho mã nguồn linh hoạt hơn và dễ duy trì hơn. Python tự động hỗ trợ tính đa hình, không cần phải khai báo rõ ràng, điều này giúp tạo ra các chương trình có khả năng thích ứng và mở rộng.

Ví dụ, giả sử chúng ta có một lớp 'Hinh' với một phương thức 'dien_tich'. Sau đó, chúng ta tạo ra hai lớp con 'HinhVuong' và 'HinhTron', mỗi lớp con đều thực hiện phương thức 'dien_tich' theo cách riêng của nó.

class Hinh:
    def dien_tich(self):
        pass

class HinhVuong(Hinh):
    def __init__(self, canh):
        self.canh = canh
    
    def dien_tich(self):
        return self.canh ** 2

class HinhTron(Hinh):
    def __init__(self, ban_kinh):
        self.ban_kinh = ban_kinh
    
    def dien_tich(self):
        return 3.14 * self.ban_kinh ** 2

def tinh_dien_tich(hinh):
    return hinh.dien_tich()

# Sử dụng
hinh_vuong = HinhVuong(5)
hinh_tron = HinhTron(7)

print(tinh_dien_tich(hinh_vuong)) # Output: 25
print(tinh_dien_tich(hinh_tron)) # Output: 153.86

Trong ví dụ trên, hàm 'tinh_dien_tich' chấp nhận bất kỳ đối tượng nào có phương thức 'dien_tich', đây chính là một ví dụ về tính đa hình. Điều này giúp chúng ta có thể mở rộng chương trình, thêm các lớp mới mà không cần thay đổi mã nguồn đã tồn tại.

Enjoying these posts? Subscribe for more