Python Nâng Cao: Trang Trí Hàm, Trình Tạo, Và Phương Thức Đặc Biệt

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**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__()__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ùng len(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ểu obj[key]
  • __iter____next__: Hỗ trợ duyệt vòng lặp
  • __enter__, __exit__: Hỗ trợ khối with

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

Thẻ: python Decorators generators iterators magic methods

Đăng vào ngày 9 tháng 7 lúc 09:21