Cách tạo và sử dụng trang trí trong Python

Tìm hiểu cách viết và áp dụng các trình trang trí trong Python. Làm chủ các chức năng gói, sửa đổi hành vi, xử lý đối số và bảo toàn siêu dữ liệu bằng gói.

Hãy thử Giải pháp này trong Trình chỉnh sửa

Tổng quan

Trình trang trí là một trong những tính năng cú pháp mạnh mẽ và tinh tế nhất của Python, cho phép bạn sửa đổi hành vi của một hàm hoặc lớp mà không cần thay đổi vĩnh viễn mã của nó. Chúng được sử dụng rộng rãi cho các mối quan tâm xuyên suốt như ghi nhật ký thời gian thực thi, thực thi xác thực người dùng, kết quả lưu vào bộ đệm (ghi nhớ) và kiểm tra điểm cuối API.

Về cơ bản, trình trang trí là một hàm bậc cao hơn lấy một hàm khác làm đối số, xác định hàm bao bọc lồng nhau đưa vào một số logic tùy chỉnh và trả về hàm bao bọc này. Python cung cấp một cú pháp tốc ký rõ ràng bằng cách sử dụng ký hiệu `@` để áp dụng các trình trang trí cho các hàm, khiến chúng trở nên trang nhã về mặt hình ảnh.

Khi viết các trình trang trí, thông thường bạn sẽ muốn hàm trang trí hỗ trợ bất kỳ số lượng đối số vị trí và từ khóa nào. Bạn có thể đạt được điều này bằng cách thiết kế hàm bao bọc lồng nhau để chấp nhận `*args` và `**kwargs` và chuyển chúng đến hàm đích. Ngoài ra, bạn nên sử dụng `functools.wraps` trên hàm bao bọc để bảo toàn siêu dữ liệu tên và chuỗi tài liệu của hàm ban đầu.

Đầu ra mã & thực thi

Tập lệnh này minh họa cách viết trình trang trí ghi nhật ký và gói một hàm để kiểm tra đầu vào, đầu ra và siêu dữ liệu.

decorators_tutorial.py
Thử trong Trình chỉnh sửa
from functools import wraps

# 1. Defining a decorator
def log_execution(func):
    @wraps(func) # Preserves original function metadata
    def wrapper(*args, **kwargs):
        print(f"[Log] Calling function: {func.__name__} with args: {args}")
        result = func(*args, **kwargs)
        print(f"[Log] Finished {func.__name__}. Result: {result}")
        return result
    return wrapper

# 2. Applying the decorator using @ syntax
@log_execution
def add_numbers(a, b):
    """Adds two numbers and returns the sum."""
    return a + b

# 3. Invoking the decorated function
sum_result = add_numbers(15, 25)
print("Sum Result:", sum_result)

# Verifying metadata preservation
print("Docstring preserved:", add_numbers.__doc__)
Đầu ra thiết bị đầu cuối
[Log] Calling function: add_numbers with args: (15, 25)
[Log] Finished add_numbers. Result: 40
Sum Result: 40
Docstring preserved: Adds two numbers and returns the sum.

Triển khai từng bước

  • Xác định hàm trang trí bên ngoài lấy hàm đích làm đối số.
  • Nhập và áp dụng @functools.wraps(func) trên hàm bao bọc lồng nhau của bạn để bảo vệ siêu dữ liệu gốc.
  • Triển khai trình bao bọc(*args, **kwargs) để nắm bắt các biến đầu vào, chèn logic và gọi hàm đích.
  • Trả về đối tượng hàm bao bọc từ khối tiêu đề trang trí.
  • Áp dụng trình trang trí bằng cách sử dụng @trang trí_name ngay phía trên chữ ký hàm đích.

Câu hỏi thường gặp

Tại sao @functools.wraps lại cần thiết bên trong trang trí?

Nếu không có lệnh bao bọc, hàm được trang trí sẽ mất danh tính ban đầu (các thuộc tính __name__ và __doc__ của nó được thay thế bằng các thuộc tính của hàm bao bọc lồng nhau), điều này khiến cho việc gỡ lỗi và xem xét nội bộ mã trở nên khó khăn.

Tôi có thể áp dụng nhiều trang trí cho một chức năng không?

Vâng! Bạn có thể xâu chuỗi các trình trang trí bằng cách xếp chồng nhiều dòng @. Python áp dụng chúng từ dưới lên (gần nhất với định nghĩa hàm được thực thi trước tiên).

Chủ đề liên quan

Tài nguyên Python được đề xuất

Mở rộng kiến thức của bạn với các hướng dẫn tương tác, bảng ghi chú và so sánh mã có liên quan.