Trang Trí Hàm (Decorators)
Trong Python, decorator là một công cụ mạnh mẽ cho phép mở rộng chức năng của hàm mà không cần thay đổi nội dung hàm gốc. Đây là kỹ thuật phổ biến trong lập trình hàm bậc cao.
Decorator Cơ Bản
Hãy tưởng tượng bạn muốn bọc một món quà đơn giản thành gói quà cầu kỳ hơn:
def mon_qua():
print("iPhone 15")
def hop_qua(func):
print("=== Hộp quà ===")
print("Bông xốp trắng")
print("Sô cô la ngọt ngào")
print("Son môi đỏ rực")
return func
mon_qua = hop_qua(mon_qua)
mon_qua()
Kết quả xuất ra sẽ bao gồm phần trang trí và món quà ban đầu. Ở đây, hop_qua chính là một decorator – hàm nhận vào một hàm khác như tham số và trả về chính nó hoặc một hàm mới.
Sử dụng cú pháp @ để làm gọn mã nguồn:
@hop_qua
def mon_qua():
print("iPhone 15")
mon_qua() # Gọi hàm đã được trang trí
Xử Lý Tham Số Với Decorator
Nếu món quà cần tùy chọn màu sắc, ta phải đảm bảo decorator có thể truyền tham số đến hàm gốc:
def hop_qua(func):
print("=== Hộp quà ===")
def qua_moi(*args, **kwargs):
if args:
mau = args[0]
print(f"Bông xốp màu {mau}")
else:
print("Bông xốp thường")
print("Sô cô la ngọt ngào")
print("Son môi đỏ rực")
ket_qua = func(*args, **kwargs)
return ket_qua
return qua_moi
@hop_qua
def mon_qua(mau_sac, phien_ban="thường"):
if phien_ban == "pro":
print(f"iPhone 15 Pro {mau_sac}")
else:
print(f"iPhone 15 {mau_sac}")
mon_qua("tím", phien_ban="pro")
Decorator này dùng *args và **kwargs để tiếp nhận mọi kiểu tham số, giúp nó linh hoạt với bất kỳ hàm nào.
Decorator Có Tham Số
Để tùy chỉnh hình dạng hộp quà theo sở thích người nhận, ta cần thêm một lớp hàm bao quanh:
def kieu_hop(hinh_dang):
def hop_qua(func):
print(f"=== {hinh_dang} quà ===")
def qua_moi(*args, **kwargs):
if args:
mau = args[0]
print(f"Bông xốp màu {mau}")
print("Sô cô la ngọt ngào")
print("Son môi đỏ rực")
return func(*args, **kwargs)
return qua_moi
return hop_qua
@kieu_hop("Trái tim")
def mon_qua(mau_sac):
print(f"iPhone 15 {mau_sac}")
mon_qua("hồng")
Cấu trúc này gồm ba tầng hàm lồng nhau: tầng ngoài nhận tham số cấu hình, tầng giữa là decorator thực sự, và tầng trong là hàm thay thế.
Trình Tạo (Generators) và Đối Tượng Lặp
Đối Tượng Lặp Được (Iterable)
Bất kỳ đối tượng nào triển khai phương thức __iter__() đều có thể dùng trong vòng lặp for. Phương thức này trả về một iterator.
Iterator
Iterator là đối tượng thực hiện giao thức lặp bằng cách định nghĩa cả __iter__() và __next__():
class DaySo:
def __init__(self, gioi_han):
self.gioi_han = gioi_han
self.hien_tai = 0
def __iter__(self):
return self
def __next__(self):
if self.hien_tai >= self.gioi_han:
raise StopIteration
self.hien_tai += 1
return self.hien_tai
so = DaySo(5)
for n in so:
print(n)
Generator
Generator là cách đơn giản để tạo iterator bằng từ khóa yield. Mỗi lần gọi next(), hàm chạy đến câu lệnh yield và tạm dừng:
def fibonacci(n):
a, b = 0, 1
count = 0
while count < n:
yield b
a, b = b, a + b
count += 1
for i in fibonacci(6):
print(i)
Generator tiết kiệm bộ nhớ vì không lưu toàn bộ dữ liệu, chỉ sinh giá trị khi cần.
Comprehension và Generator Expression
Comprehension giúp viết code ngắn gọn hơn. Ví dụ với danh sách người dùng:
du_lieu = [
{'ten': 'An', 'gioi': 'nam', 'tuoi': 14},
{'ten': 'Binh', 'gioi': 'nu', 'tuoi': 16},
{'ten': 'Cuong', 'gioi': 'nam', 'tuoi': 20}
]
Lấy tên tất cả người dùng:
danh_sach_ten = [item['ten'] for item in du_lieu]
Thêm tiền tố:
danh_sach_ten = [f"Họ tên: {item['ten']}" for item in du_lieu]
Lọc theo điều kiện:
ten_lon_hon_15 = [item['ten'] for item in du_lieu if item['tuoi'] > 15]
Dictionary comprehension:
tuoi_theo_ten = {item['ten']: item['tuoi'] for item in du_lieu}
Chuyển list comprehension thành generator expression bằng cách dùng dấu ngoặc tròn ():
generator_ten = (item['ten'] for item in du_lieu)
Generator expression không thực thi ngay lập tức, chỉ sinh giá trị khi duyệt qua.
Phương Thức Đặc Biệt (Magic Methods)
Các phương thức bắt đầu và kết thúc bằng hai gạch dưới __ cho phép tuỳ chỉnh hành vi của lớp. Một số phương thức quan trọng:
__init__: Khởi tạo đối tượng__str__: Chuỗi mô tả khi in đối tượng__len__: Định nghĩa độ dài khi dùnglen(obj)__eq__,__lt__,__gt__: So sánh đối tượng__add__: Cộng hai đối tượng__getitem__,__setitem__: Truy cập phần tử kiểuobj[key]__iter__và__next__: Hỗ trợ duyệt vòng lặp__enter__,__exit__: Hỗ trợ khốiwith
Ví dụ tuỳ chỉnh biểu diễn chuỗi:
class SinhVien:
def __init__(self, ten, tuoi):
self.ten = ten
self.tuoi = tuoi
def __str__(self):
return f"Sinh viên {self.ten}, {self.tuoi} tuổi"
sv = SinhVien("Minh", 20)
print(sv) # In ra: Sinh viên Minh, 20 tuổi