Khóa học python

Tính Đóng Gói trong Python

0 phút đọc

Tính đóng gói (Encapsulation) là một trong những nguyên lý cơ bản của lập trình hướng đối tượng (OOP). Nó đề cập đến việc gói gọn dữ liệu (các thuộc tính) và các phương thức (hành vi) liên quan vào trong một đối tượng duy nhất. Tính đóng gói giúp bảo vệ dữ liệu khỏi sự truy cập và thay đổi không mong muốn từ bên ngoài, đồng thời cung cấp một giao diện rõ ràng và có kiểm soát để tương tác với đối tượng.

Lợi Ích của Tính Đóng Gói

  1. Bảo vệ dữ liệu: Ngăn chặn sự truy cập và thay đổi dữ liệu không mong muốn từ bên ngoài.
  2. Tính bảo trì: Dễ dàng thay đổi và nâng cấp mã nguồn mà không ảnh hưởng đến các phần khác của chương trình.
  3. Tính rõ ràng: Cung cấp một giao diện rõ ràng và có kiểm soát để tương tác với đối tượng.
  4. Tính tái sử dụng: Các đối tượng được đóng gói có thể dễ dàng tái sử dụng trong các phần khác của chương trình hoặc trong các dự án khác.

Tính Đóng Gói trong Python

Trong Python, tính đóng gói được thực hiện bằng cách sử dụng các thuộc tính và phương thức công khai (public), bảo vệ (protected), và riêng tư (private).

Thuộc Tính và Phương Thức Công Khai (Public)

Các thuộc tính và phương thức công khai có thể được truy cập từ bất kỳ đâu, cả bên trong và bên ngoài lớp.

class Person:
    def __init__(self, name, age):
        self.name = name  # Thuộc tính công khai
        self.age = age    # Thuộc tính công khai

    def display_info(self):  # Phương thức công khai
        print(f"Name: {self.name}, Age: {self.age}")

# Tạo đối tượng của lớp Person
person = Person("John", 30)

# Truy cập thuộc tính và phương thức công khai
print(person.name)  # Output: John
print(person.age)   # Output: 30
person.display_info()  # Output: Name: John, Age: 30

Thuộc Tính và Phương Thức Bảo Vệ (Protected)

Các thuộc tính và phương thức bảo vệ được định nghĩa bằng cách thêm một dấu gạch dưới _ trước tên thuộc tính hoặc phương thức. Chúng có thể được truy cập từ bên trong lớp và các lớp con, nhưng không nên truy cập từ bên ngoài lớp.

class Person:
    def __init__(self, name, age):
        self._name = name  # Thuộc tính bảo vệ
        self._age = age    # Thuộc tính bảo vệ

    def _display_info(self):  # Phương thức bảo vệ
        print(f"Name: {self._name}, Age: {self._age}")

# Tạo đối tượng của lớp Person
person = Person("John", 30)

# Truy cập thuộc tính và phương thức bảo vệ (không khuyến khích)
print(person._name)  # Output: John
print(person._age)   # Output: 30
person._display_info()  # Output: Name: John, Age: 30

Thuộc Tính và Phương Thức Riêng Tư (Private)

Các thuộc tính và phương thức riêng tư được định nghĩa bằng cách thêm hai dấu gạch dưới __ trước tên thuộc tính hoặc phương thức. Chúng chỉ có thể được truy cập từ bên trong lớp và không thể truy cập từ bên ngoài lớp.

class Person:
    def __init__(self, name, age):
        self.__name = name  # Thuộc tính riêng tư
        self.__age = age    # Thuộc tính riêng tư

    def __display_info(self):  # Phương thức riêng tư
        print(f"Name: {self.__name}, Age: {self.__age}")

    def get_info(self):  # Phương thức công khai để truy cập thuộc tính riêng tư
        self.__display_info()

# Tạo đối tượng của lớp Person
person = Person("John", 30)

# Truy cập thuộc tính và phương thức riêng tư (sẽ gây lỗi)
# print(person.__name)  # AttributeError
# print(person.__age)   # AttributeError
# person.__display_info()  # AttributeError

# Truy cập thuộc tính và phương thức riêng tư thông qua phương thức công khai
person.get_info()  # Output: Name: John, Age: 30

Sử Dụng Getter và Setter

Getter và setter là các phương thức được sử dụng để truy cập và cập nhật các thuộc tính riêng tư của một lớp. Chúng cung cấp một giao diện có kiểm soát để tương tác với các thuộc tính này.

Ví dụ về Getter và Setter

class Person:
    def __init__(self, name, age):
        self.__name = name  # Thuộc tính riêng tư
        self.__age = age    # Thuộc tính riêng tư

    # Getter cho thuộc tính name
    def get_name(self):
        return self.__name

    # Setter cho thuộc tính name
    def set_name(self, name):
        self.__name = name

    # Getter cho thuộc tính age
    def get_age(self):
        return self.__age

    # Setter cho thuộc tính age
    def set_age(self, age):
        if age > 0:
            self.__age = age
        else:
            print("Age must be positive")

# Tạo đối tượng của lớp Person
person = Person("John", 30)

# Sử dụng getter để truy cập thuộc tính riêng tư
print(person.get_name())  # Output: John
print(person.get_age())   # Output: 30

# Sử dụng setter để cập nhật thuộc tính riêng tư
person.set_name("Alice")
person.set_age(25)
print(person.get_name())  # Output: Alice
print(person.get_age())   # Output: 25

# Thử cập nhật thuộc tính age với giá trị không hợp lệ
person.set_age(-5)  # Output: Age must be positive

Sử Dụng Decorator @property

Python cung cấp một cách tiện lợi để định nghĩa getter và setter bằng cách sử dụng decorator @property. Điều này giúp mã nguồn trở nên ngắn gọn và dễ đọc hơn.

Ví dụ về @property

class Person:
    def __init__(self, name, age):
        self.__name = name  # Thuộc tính riêng tư
        self.__age = age    # Thuộc tính riêng tư

    # Getter cho thuộc tính name
    @property
    def name(self):
        return self.__name

    # Setter cho thuộc tính name
    @name.setter
    def name(self, name):
        self.__name = name

    # Getter cho thuộc tính age
    @property
    def age(self):
        return self.__age

    # Setter cho thuộc tính age
    @age.setter
    def age(self, age):
        if age > 0:
            self.__age = age
        else:
            print("Age must be positive")

# Tạo đối tượng của lớp Person
person = Person("John", 30)

# Sử dụng getter để truy cập thuộc tính riêng tư
print(person.name)  # Output: John
print(person.age)   # Output: 30

# Sử dụng setter để cập nhật thuộc tính riêng tư
person.name = "Alice"
person.age = 25
print(person.name)  # Output: Alice
print(person.age)   # Output: 25

# Thử cập nhật thuộc tính age với giá trị không hợp lệ
person.age = -5  # Output: Age must be positive

Tính Đóng Gói và Kế Thừa

Tính đóng gói cũng có thể được kết hợp với tính kế thừa để tạo ra các lớp con mở rộng chức năng của lớp cha mà không làm lộ các chi tiết triển khai bên trong.

Ví dụ về Tính Đóng Gói và Kế Thừa

class Animal:
    def __init__(self, name):
        self.__name = name  # Thuộc tính riêng tư

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

    @name.setter
    def name(self, name):
        self.__name = name

    def make_sound(self):
        raise NotImplementedError("Subclass must implement abstract method")

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

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

# Tạo các đối tượng của lớp Dog và Cat
dog = Dog("Buddy")
cat = Cat("Whiskers")

# Truy cập thuộc tính name và gọi phương thức make_sound
print(dog.name)  # Output: Buddy
print(dog.make_sound())  # Output: Bark

print(cat.name)  # Output: Whiskers
print(cat.make_sound())  # Output: Meow

Trong ví dụ trên, lớp Animal định nghĩa một thuộc tính riêng tư __name và một phương thức trừu tượng make_sound. Các lớp con DogCat kế thừa từ lớp Animal và triển khai phương thức make_sound.

Kết Luận

Tính đóng gói là một nguyên lý quan trọng trong lập trình hướng đối tượng, giúp bảo vệ dữ liệu và cung cấp một giao diện rõ ràng và có kiểm soát để tương tác với đối tượng. Python cung cấp nhiều cách để thực hiện tính đóng gói, bao gồm sử dụng các thuộc tính và phương thức công khai, bảo vệ, và riêng tư, cũng như sử dụng getter và setter. Hiểu và sử dụng đúng tính đóng gói sẽ giúp bạn viết mã nguồn rõ ràng, dễ bảo trì và hiệu quả hơn. Hy vọng bài viết này đã cung cấp cho bạn một cái nhìn tổng quan và chi tiết về tính đóng gói trong Python.

Avatar
Được viết bởi

TechMely Team

Gợi ý câu hỏi phỏng vấn

entry

Bạn có thể nói sự khác biệt giữa cấu trúc dữ liệu tuyến tính và phi tuyến tính?

entry

Danh sách liên kết là tuyến tính hay phi tuyến tính?

entry

Làm thế nào để gọi hàm constructor của lớp cơ sở từ lớp con trong TypeScript?

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào