Hướng dẫn về Python Decorator dành cho lập trình viên nâng cao

Trình trang trí Python là một công cụ mạnh mẽ và linh hoạt để sửa đổi hành vi của các hàm hoặc phương thức. Chúng cho phép các lập trình viên mở rộng hoặc thay đổi chức năng của các đối tượng có thể gọi theo cách rõ ràng, dễ đọc và dễ bảo trì. Bài viết này khám phá các khái niệm nâng cao liên quan đến trình trang trí Python, bao gồm trình trang trí lồng nhau, đối số trình trang trí và trình trang trí dựa trên lớp.

Decorator là gì?

Decorator là các hàm sửa đổi hành vi của một hàm khác. Chúng bao bọc một hàm khác để mở rộng hành vi của hàm đó mà không sửa đổi rõ ràng mã của hàm đó. Decorator được định nghĩa bằng cú pháp @decorator_name và được đặt phía trên định nghĩa hàm.

Cú pháp trang trí cơ bản

Một trình trang trí đơn giản lấy một hàm làm đối số, định nghĩa một hàm bên trong bổ sung một số hành vi, sau đó trả về hàm bên trong.

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

Các hàm trang trí có đối số

Decorator có thể linh hoạt hơn bằng cách chấp nhận các đối số. Để tạo một decorator như vậy, bạn cần viết một hàm trả về một decorator. Điều này cho phép thêm hành vi động hơn vào decorator.

def repeat(num_times):
    def decorator_repeat(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Bộ trang trí lồng nhau

Decorator có thể được lồng nhau để kết hợp nhiều hành vi. Ví dụ, chúng ta có thể sử dụng hai hoặc nhiều decorator trên một hàm duy nhất.

def uppercase_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

def repeat_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + result
    return wrapper

@repeat_decorator
@uppercase_decorator
def say_word(word):
    return word

print(say_word("hello"))

Trình trang trí dựa trên lớp

Trong Python, các trình trang trí cũng có thể được triển khai dưới dạng lớp bằng cách sử dụng phương thức __call__. Các trình trang trí dựa trên lớp hữu ích khi bạn cần quản lý trạng thái và hành vi phức tạp hơn.

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f"Call {self.num_calls} of {self.func.__name__!r}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()
say_hello()

Sử dụng functools.wraps để bảo toàn siêu dữ liệu

Khi bạn viết trình trang trí, hàm được trang trí sẽ mất siêu dữ liệu gốc, chẳng hạn như tên và docstring. Trình trang trí functools.wraps có thể được sử dụng để sao chép siêu dữ liệu của hàm gốc vào hàm bao bọc.

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Wrapper function executed before", func.__name__)
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def display_info(name, age):
    """Displays name and age."""
    print(f"display_info ran with arguments ({name}, {age})")

print(display_info.__name__)  # Output: display_info
print(display_info.__doc__)   # Output: Displays name and age.

Phần kết luận

Trình trang trí Python là một tính năng mạnh mẽ cho phép thiết kế mã linh hoạt và sửa đổi hành vi. Sử dụng nâng cao, chẳng hạn như trình trang trí lồng nhau, trình trang trí có đối số và trình trang trí dựa trên lớp, có thể cung cấp nhiều chức năng và khả năng đọc hơn cho các chương trình Python. Bằng cách hiểu và sử dụng trình trang trí đúng cách, các nhà phát triển có thể viết mã ngắn gọn, hiệu quả và dễ đọc hơn.