Python - Các Bộ Điều Khiển Truy Cập

Xin chào các bạn nhà lập trình Python mới! Hôm nay, chúng ta sẽ bắt đầu hành trình thú vị vào thế giới các Bộ Điều Khiển Truy Cập trong Python. Đừng lo lắng nếu bạn mới bắt đầu học lập trình; tôi sẽ hướng dẫn bạn qua khái niệm này bước به bước, với nhiều ví dụ và giải thích kèm theo. Hãy bắt đầu nào!

Python - Access Modifiers

Các Bộ Điều Khiển Truy Cập trong Python

Trong lập trình hướng đối tượng, các bộ điều khiển truy cập được sử dụng để kiểm soát khả năng xem và truy cập của các thành viên lớp (thuộc tính và phương thức). Mặc dù nhiều ngôn ngữ lập trình có các bộ điều khiển truy cập nghiêm ngặt như công khai, riêng tư và được bảo vệ, Python theo phương pháp nhẹ nhàng hơn. Nó tuân theo triết lý thường được gọi là "Chúng ta đều là người lớn đồng ý".

Trong Python, chúng ta có ba loại bộ điều khiển truy cập:

  1. Công khai
  2. Được bảo vệ
  3. Riêng tư

Hãy khám phá mỗi loại này với các ví dụ.

Thành Viên Công Khai

Trong Python, tất cả các thành viên đều là công khai theo mặc định. Điều này có nghĩa là chúng có thể được truy cập từ bên ngoài lớp. Dưới đây là một ví dụ:

class SinhVien:
def __init__(self, ten, tuoi):
self.ten = ten  # Thuộc tính công khai
self.tuoi = tuoi  # Thuộc tính công khai

def hien_thi_thong_tin(self):  # Phương thức công khai
print(f"Tên: {self.ten}, Tuổi: {self.tuoi}")

# Tạo một thể hiện của SinhVien
sinh_vien_1 = SinhVien("Alice", 20)

# Truy cập các thành viên công khai
print(sinh_vien_1.ten)  # Output: Alice
sinh_vien_1.hien_thi_thong_tin()  # Output: Tên: Alice, Tuổi: 20

Trong ví dụ này, ten, tuoi, và hien_thi_thong_tin() đều là các thành viên công khai. Chúng ta có thể truy cập chúng trực tiếp từ bên ngoài lớp.

Thành Viên Được Bảo Vệ

Các thành viên được bảo vệ được đánh dấu bằng việc thêm dấu gạch dưới đơn (_) trước tên thành viên. Chúng không thực sự riêng tư và vẫn có thể được truy cập từ bên ngoài lớp, nhưng đây là quy ước để xem chúng là chỉ sử dụng nội bộ.

class NhanVien:
def __init__(self, ten, luong):
self._ten = ten      # Thuộc tính được bảo vệ
self._luong = luong  # Thuộc tính được bảo vệ

def _hien_thi_luong(self):  # Phương thức được bảo vệ
print(f"{self._ten}'s lương là ${self._luong}")

# Tạo một thể hiện của NhanVien
nhan_vien_1 = NhanVien("Bob", 50000)

# Truy cập các thành viên được bảo vệ (Lưu ý: Điều này có thể nhưng không khuyến khích)
print(nhan_vien_1._ten)  # Output: Bob
nhan_vien_1._hien_thi_luong()  # Output: Bob's lương là $50000

Mặc dù chúng ta có thể truy cập _ten, _luong, và _hien_thi_luong(), nhưng thường không nên làm điều đó từ bên ngoài lớp hoặc các lớp con.

Thành Viên Riêng Tư

Các thành viên riêng tư được đánh dấu bằng việc thêm dấu gạch dưới kép (__) trước tên. Python thực hiện việc đổi tên nội bộ cho các thành viên này, làm cho chúng khó (nhưng không不可能) truy cập từ bên ngoài lớp.

class TaiKhoanNganHang:
def __init__(self, so_tai_khoan, so_du):
self.__so_tai_khoan = so_tai_khoan  # Thuộc tính riêng tư
self.__so_du = so_du                # Thuộc tính riêng tư

def __hien_thi_so_du(self):  # Phương thức riêng tư
print(f"Số dư: ${self.__so_du}")

def hien_thi_so_du_cong_khai(self):
self.__hien_thi_so_du()

# Tạo một thể hiện của TaiKhoanNganHang
tai_khoan_1 = TaiKhoanNganHang("123456", 1000)

# Thử truy cập các thành viên riêng tư
# print(tai_khoan_1.__so_tai_khoan)  # Điều này sẽ gây ra AttributeError
# tai_khoan_1.__hien_thi_so_du()      # Điều này cũng sẽ gây ra AttributeError

# Truy cập phương thức riêng tư thông qua phương thức công khai
tai_khoan_1.hien_thi_so_du_cong_khai()  # Output: Số dư: $1000

Trong ví dụ này, __so_tai_khoan, __so_du, và __hien_thi_so_du() đều là các thành viên riêng tư. Thử truy cập chúng trực tiếp từ bên ngoài lớp sẽ gây ra lỗi AttributeError.

Đổi Tên Nội Bộ

Nhớ khi tôi nói rằng các thành viên riêng tư trong Python không thực sự riêng tư? Điều này là do cơ chế gọi là đổi tên nội bộ. Khi bạn tạo một thành viên riêng tư bằng cách sử dụng dấu gạch dưới kép, Python thay đổi tên nội bộ của nó để làm cho nó khó truy cập ngầm.

Dưới đây là cách nó hoạt động:

class TenManglingDemo:
def __init__(self):
self.__private_var = "Tôi là riêng tư!"

demo = TenManglingDemo()
print(dir(demo))
# Output: [..., '_TenManglingDemo__private_var', ...]

# Truy cập biến riêng tư bằng cách sử dụng tên đã đổi
print(demo._TenManglingDemo__private_var)  # Output: Tôi là riêng tư!

Như bạn thấy, Python đổi tên __private_var thành _TenManglingDemo__private_var. Đây là cơ chế đổi tên nội bộ đang hoạt động!

Đối Tượng Thuộc tính trong Python

Hàm property() trong Python là một hàm dựng sẵn để tạo và trả về một đối tượng thuộc tính. Nó là một cách để thêm các phương thức getter, setter và deleter vào các thuộc tính lớp.

Dưới đây là một ví dụ:

class NhietDo:
def __init__(self, celsius):
self._celsius = celsius

def get_fahrenheit(self):
return (self._celsius * 9/5) + 32

def set_fahrenheit(self, fahrenheit):
self._celsius = (fahrenheit - 32) * 5/9

fahrenheit = property(get_fahrenheit, set_fahrenheit)

# Sử dụng thuộc tính
nhiet_do = NhietDo(25)
print(nhiet_do.fahrenheit)  # Output: 77.0

nhiet_do.fahrenheit = 86
print(nhiet_do._celsius)  # Output: 30.0

Trong ví dụ này, fahrenheit là một thuộc tính cho phép chúng ta lấy và đặt nhiệt độ theo độ F làm trong Celsius.

Các Phương Thức Getter và Setter

Các phương thức getter và setter được sử dụng để lấy và đặt giá trị của các thuộc tính lớp. Chúng cung cấp cách để truy cập và thay đổi các thuộc tính riêng tư trong khi duy trì tính đóng gói.

Dưới đây là một ví dụ sử dụng décorator @property, cách tiếp cận thân thiện hơn với Python để thực hiện các phương thức getter và setter:

class Nguoi:
def __init__(self, ten, tuoi):
self._ten = ten
self._tuoi = tuoi

@property
def ten(self):
return self._ten

@ten.setter
def ten(self, gia_tri):
if not isinstance(gia_tri, str):
raise ValueError("Tên phải là một chuỗi")
self._ten = gia_tri

@property
def tuoi(self):
return self._tuoi

@tuoi.setter
def tuoi(self, gia_tri):
if not isinstance(gia_tri, int) or gia_tri < 0:
raise ValueError("Tuổi phải là một số nguyên dương")
self._tuoi = gia_tri

# Sử dụng các phương thức getter và setter
nguoi = Nguoi("Charlie", 30)
print(nguoi.ten)  # Output: Charlie

nguoi.ten = "David"
print(nguoi.ten)  # Output: David

try:
nguoi.tuoi = -5
except ValueError as e:
print(e)  # Output: Tuổi phải là một số nguyên dương

Trong ví dụ này, chúng ta đã tạo các phương thức getter và setter cho tentuoi. Các phương thức setter bao gồm kiểm tra để đảm bảo rằng các giá trị được đặt đạt được các tiêu chuẩn cụ thể.

Dưới đây là bảng tổng kết các phương thức mà chúng ta đã thảo luận, trong định dạng Markdown:

Phương thức Mô tả Ví dụ
Công khai Có thể truy cập từ bất kỳ đâu self.ten
Được bảo vệ Có thể truy cập trong lớp và các lớp con (theo quy ước) self._ten
Riêng tư Đổi tên nội bộ để hạn chế truy cập self.__ten
Thuộc tính Tạo một đối tượng thuộc tính property(get_method, set_method)
Getter Phương thức để lấy giá trị của thuộc tính @property
Setter Phương thức để đặt giá trị của thuộc tính @attribute.setter

Và đó là tất cả! Chúng ta đã bao gồm các bộ điều khiển truy cập trong Python, đổi tên nội bộ, đối tượng thuộc tính, và các phương thức getter và setter. Nhớ rằng, cách tiếp cận của Python đối với kiểm soát truy cập là nhiều hơn về việc tuân theo quy ước và tín nhiệm hơn là các quy định nghiêm ngặt. Khi bạn tiếp tục hành trình với Python, bạn sẽ thấy rằng sự linh hoạt này cho phép mã nguồn sạch và dễ đọc trong khi vẫn cung cấp cách để thực hiện tính đóng gói khi cần thiết.

Hãy tiếp tục tập luyện, giữ được sự tò mò và hạnh phúc khi lập trình!

Credits: Image by storyset