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!
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:
- Công khai
- Được bảo vệ
- 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 ten
và tuoi
. 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