Python - Đóng gói (Encapsulation): Hướng dẫn cho Người Mới Bắt Đầu

Xin chào các nhà phép thuật Python tương lai! Hôm nay, chúng ta sẽ bơi lội vào thế giới thần bí của việc đóng gói (encapsulation). Đừng lo lắng nếu từ này có vẻ như một lời khai từ Harry Potter - đến cuối bài học này, bạn sẽ kiểm soát khái niệm này như một chuyên gia!

Python - Encapsulation

Đóng gói là gì?

Đóng gói như có một cuộn nhật ký bí mật với khóa. Đó là cách để đóng gói dữ liệu (những bài ghi nhật ký) và các phương thức làm việc trên dữ liệu đó (hành động viết vào nhật ký) thành một đơn vị duy nhất, đồng thời cũng kiểm soát quyền truy cập vào dữ liệu đó. Trong Python, chúng ta đạt được điều này bằng cách sử dụng các lớp (class).

Hãy bắt đầu với một ví dụ đơn giản:

class Diary:
def __init__(self):
self.entries = []

def add_entry(self, entry):
self.entries.append(entry)

def get_entries(self):
return self.entries

my_diary = Diary()
my_diary.add_entry("Dear Diary, today I learned about encapsulation!")
print(my_diary.get_entries())

Trong ví dụ này, Diary là lớp của chúng ta. Nó có một thuộc tính riêng entries (nội dung nhật ký bí mật) và hai phương thức để tương tác với nó. Đây là đóng gói đang hoạt động!

Thực hiện Đóng gói trong Python

Thuộc tính Riêng

Trong Python, chúng ta sử dụng quy ước đặt tiền tố dấu gạch dưới để cho biết thuộc tính là riêng. Hãy cập nhật lớp Diary của chúng ta:

class Diary:
def __init__(self):
self._entries = []  # Chú ý dấu gạch dưới

def add_entry(self, entry):
self._entries.append(entry)

def get_entries(self):
return self._entries.copy()  # Trả về bản sao để bảo vệ gốc

my_diary = Diary()
my_diary.add_entry("I love Python!")
print(my_diary.get_entries())
# Điều này sẽ hoạt động, nhưng không khuyến khích:
print(my_diary._entries)

Dấu gạch dưới nhắc nhở các lập trình viên khác, "Ôi, đây là riêng! Đừng chạm trực tiếp nó!" Nhưng trong Python, đó chỉ là một thỏa thuận của người phép - bạn vẫn có thể truy cập, nhưng không nên.

Định dạng Thuộc tính

Để kiểm soát thêm, chúng ta có thể sử dụng các định dạng thuộc tính. Chúng giống như các quân vệ bảo vệ các thuộc tính của chúng ta:

class Diary:
def __init__(self):
self._entries = []

def add_entry(self, entry):
self._entries.append(entry)

@property
def entries(self):
return self._entries.copy()

my_diary = Diary()
my_diary.add_entry("Properties are cool!")
print(my_diary.entries)  # Điều này hoạt động
# my_diary.entries = []  # Điều này sẽ gây ra lỗi

Định dạng @property cho phép chúng ta truy cập entries như một thuộc tính, nhưng thực chất nó gọi một phương thức ẩn sau khung.

Các phương thức Setter và Getter

Đôi khi, chúng ta muốn cho phép sửa đổi kiểm soát thuộc tính của mình. Nhập các phương thức setter:

class Diary:
def __init__(self):
self._entries = []

def add_entry(self, entry):
self._entries.append(entry)

@property
def entries(self):
return self._entries.copy()

@entries.setter
def entries(self, new_entries):
if isinstance(new_entries, list):
self._entries = new_entries
else:
raise ValueError("Entries must be a list")

my_diary = Diary()
my_diary.entries = ["Day 1", "Day 2"]  # Điều này hoạt động bây giờ
print(my_diary.entries)
my_diary.entries = "Not a list"  # Điều này sẽ gây ra lỗi

Bây giờ chúng ta có thể đặt entries trực tiếp, nhưng chỉ nếu nó là một danh sách. Nhật ký của chúng ta trở nên phức tạp hơn!

Tại sao Sử dụng Đóng gói?

  1. Bảo vệ Dữ liệu: Ngăn chặn sự sửa đổi ngẫu nhiên của dữ liệu.
  2. Linh hoạt: Bạn có thể thay đổi cách thực hiện nội bộ mà không ảnh hưởng đến mã ngoại vi.
  3. Kiểm soát: Bạn quyết định cách dữ liệu của bạn được truy cập và sửa đổi.

Tưởng tượng nếu bất kỳ ai cũng có thể viết vào nhật ký của bạn mà không có sự cho phép của bạn - sự hỗn loạn! Đóng gói giữ cho mọi thứ có thể hợp lý và an toàn.

Kỹ thuật Đóng gói Nâng cao

Tên Mã hóa

Khi bạn thực sự muốn giữ điều gì đó là riêng, Python cung cấp tên mã hóa:

class SuperSecretDiary:
def __init__(self):
self.__ultra_private = "My deepest secrets"

def reveal_secrets(self):
return self.__ultra_private

diary = SuperSecretDiary()
print(diary.reveal_secrets())  # Điều này hoạt động
# print(diary.__ultra_private)  # Điều này gây ra lỗi AttributeError
print(diary._SuperSecretDiary__ultra_private)  # Điều này hoạt động, nhưng thực sự không khuyến khích!

Dấu gạch đôi khi gây ra Python "mã hóa" tên, làm cho nó khó (nhưng không不可能) truy cập từ bên ngoài lớp.

Đóng gói với Thuộc tính

Hãy tạo một ví dụ phức tạp hơn - một tài khoản ngân hàng:

class BankAccount:
def __init__(self, initial_balance=0):
self._balance = initial_balance

@property
def balance(self):
return self._balance

@balance.setter
def balance(self, value):
if value < 0:
raise ValueError("Balance cannot be negative")
self._balance = value

def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount

def withdraw(self, amount):
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
if amount > self.balance:
raise ValueError("Insufficient funds")
self.balance -= amount

account = BankAccount(1000)
print(account.balance)  # 1000
account.deposit(500)
print(account.balance)  # 1500
account.withdraw(200)
print(account.balance)  # 1300
# account.balance = -500  # Điều này sẽ gây ra lỗi ValueError

Lớp BankAccount đóng gói số dư, đảm bảo rằng nó không thể trở thành số âm và rằng các giao dịch gửi và rút là hợp lệ.

Bảng Phương thức Đóng gói

Phương thức Mô tả Ví dụ
Dấu gạch dưới Tiền tố Đánh dấu thuộc tính riêng self._private_var
Định dạng Thuộc tính Tạo getter cho thuộc tính @property
Định dạng Setter Tạo setter cho thuộc tính @attribute.setter
Tên Mã hóa Tạo thuộc tính riêng mạnh mẽ self.__very_private

Kết luận

Đóng gói như là một người chăm sóc trách nhiệm của dữ liệu của bạn. Nó không phải là về việc bí mật, mà về việc đảm bảo rằng dữ liệu của bạn được xử lý với tinh thần và ý định. Khi bạn tiếp tục hành trình Python của mình, bạn sẽ tìm thấy đóng gói là một công cụ không thể thiếu để tạo ra mã mạnh mẽ và dễ bảo trì.

Nhớ rồi, các bạn Pythonista trẻ, với quyền lực lớn đến đến trách nhiệm lớn. Sử dụng đóng gói một cách khôn ngoan, và mã của bạn sẽ cảm ơn bạn!

Bây giờ, hãy tiến lên và đóng gói! Và đừng quên viết vào nhật ký (được bảo vệ tốt) của bạn về tất cả những điều thú vị về Python mà bạn đang học. Chúc bạn có một ngày编程 vui vẻ!

Credits: Image by storyset