Các nhà phát triển Python có thể mở rộng và sửa đổi hành vi của các hàm, phương thức hoặc lớp có thể gọi (callable) mà không cần sửa đổi vĩnh viễn chính đối tượng callable đó bằng cách sử dụng decorators (trang trí). Nói ngắn gọn, decorators là các đối tượng callable được dùng để sửa đổi hàm hoặc lớp.
Function decorators là các hàm chấp nhận tham chiếu hàm làm đối số, thêm một lớp bao (wrapper) xung quanh chúng và trả về hàm mới đã được bao bọc.
Hãy hiểu function decorator qua một ví dụ:
Code 1
@decorator def func(arg): return "value"
Đoạn code trên tương đương với:
Code 2
def func(arg): return "value" func = decorator(func)
Từ ví dụ trên, ta thấy decorator đơn giản là một hàm khác nhận một hàm làm đối số và trả về một hàm.
Decorators cơ bản "trang trí" hoặc "bao bọc" một hàm khác và cho phép bạn thực thi code trước và sau khi hàm được bao bọc chạy, như được giải thích trong ví dụ dưới đây:
def our_decorator(func): def function_wrapper(x): print("Trước khi gọi " + func.__name__) func(x) print("Sau khi gọi " + func.__name__) return function_wrapper def foo(x): print("Chào, foo đã được gọi với " + str(x)) print("Gọi foo trước khi trang trí:") foo("Hi") print("Chúng ta trang trí foo với f:") foo = our_decorator(foo) print("Gọi foo sau khi trang trí:") foo(90) Kết quả
Gọi foo trước khi trang trí: Chào, foo đã được gọi với Hi Chúng ta trang trí foo với f: Gọi foo sau khi trang trí: Trước khi gọi foo Chào, foo đã được gọi với 90 Sau khi gọi foo
Nếu bạn thấy ví dụ trên hơi phức tạp, hãy viết decorator đơn giản nhất có thể:
def null_decorator(func): return func
Decorator null_decorator trên là một callable (hàm), nó nhận một callable khác làm đầu vào và trả về chính callable đầu vào đó mà không sửa đổi nó.
Hãy mở rộng decorator đơn giản nhất ở trên bằng cách trang trí (bao bọc) một hàm khác.
def null_decorator(func): return func def greet(): return "Hello, Python!" greet = null_decorator(greet) >>> greet() 'Hello, Python!'
Ở trên, chúng ta đã định nghĩa hàm greet và ngay lập tức trang trí nó bằng cách chạy nó qua hàm null_decorator.
Cách viết đơn giản hơn cho chương trình trang trí Python ở trên (thay vì gọi tường minh null_decorator trên greet và gán lại biến greet) là sử dụng cú pháp @ của Python để trang trí hàm trong một bước:
@null_decorator def greet(): return "Hello, Python!" >>> greet() 'Hello, Python!'