Các trình trang trí (decorators) trong Python
Bài viết này giải thích về các trình trang trí (decorators) trong Python.
YouTube Video
Các trình trang trí (decorators) trong Python
Các trình trang trí (decorators) trong Python là một tính năng mạnh mẽ được sử dụng để bổ sung chức năng mới vào các hàm hoặc phương thức. Các trình trang trí (decorators) cho phép bạn bổ sung chức năng mới mà không cần chỉnh sửa mã nguồn hiện có, từ đó cải thiện khả năng tái sử dụng và bảo trì mã.
Cơ bản về Trình trang trí (Decorators)
Các trình trang trí (decorators) trong Python hoạt động bằng cách nhận một hàm làm tham số và trả về một hàm mới với chức năng được bổ sung. Bằng cách sử dụng các trình trang trí (decorators), bạn có thể dễ dàng thêm các tác vụ tiền xử lý hoặc hậu xử lý vào các hàm.
Nếu không sử dụng các trình trang trí (decorators), việc điều chỉnh hành vi của một hàm sẽ đòi hỏi phải chỉnh sửa trực tiếp hàm đó. Với các trình trang trí, bạn có thể mở rộng chức năng mà không cần sửa đổi triển khai ban đầu.
Cấu trúc cơ bản của một Trình trang trí (Decorator)
1def my_decorator(func):
2 def wrapper():
3 print("Before the function call")
4 func()
5 print("After the function call")
6 return wrapper
7
8@my_decorator
9def say_hello():
10 print("Hello!")
11
12say_hello()
Trong ví dụ này, hàm my_decorator
đóng vai trò là một trình trang trí (decorator), bao bọc xung quanh hàm say_hello
. Trình trang trí (decorator) được áp dụng bằng cú pháp @my_decorator
, và khi hàm say_hello()
được gọi, các tác vụ tiền xử lý và hậu xử lý do trình trang trí cung cấp sẽ tự động được thực thi.
Cách thức Hoạt động của Trình trang trí (Decorators)
Các trình trang trí hoạt động theo các bước sau.
-
Trình trang trí (decorator) nhận một hàm (hoặc phương thức) làm tham số đầu vào.
-
Nó định nghĩa một hàm bao bọc để thực thi hàm gốc.
-
Hàm bao bọc thực hiện các xử lý bổ sung trước hoặc sau khi thực thi hàm gốc.
-
Trình trang trí (decorator) trả về hàm bao bọc. Kết quả là, hàm gốc được thay thế bằng một hàm mới đã được trang trí.
Trình trang trí (Decorators) cho các Hàm có Tham số
Khi áp dụng một trình trang trí (decorator) cho một hàm có tham số, hàm bao bọc cần được điều chỉnh để chấp nhận những tham số đó.
1def my_decorator(func):
2 def wrapper(*args, **kwargs):
3 print("Before the function call")
4 result = func(*args, **kwargs)
5 print("After the function call")
6 return result
7 return wrapper
8
9@my_decorator
10def greet(name):
11 print(f"Hello, {name}!")
12
13greet("Alice")
Bằng cách sử dụng *args
và **kwargs
, bạn có thể xử lý các hàm chấp nhận bất kỳ số lượng tham số hoặc tham số từ khóa nào. Điều này cho phép trình trang trí (decorators) được áp dụng một cách tổng quát cho các hàm với bất kỳ loại tham số nào.
Ví dụ về áp dụng Decorators
Decorator để Ghi nhật ký
Decorators thường được sử dụng để thêm chức năng ghi nhật ký. Ví dụ, bằng cách tạo một decorator ghi nhật ký trước và sau khi thực thi một hàm, bạn có thể ghi lại khi nào hàm được gọi và mất bao lâu để thực thi.
1import time
2
3def log_time(func):
4 def wrapper(*args, **kwargs):
5 start_time = time.time()
6 print(f"Calling function '{func.__name__}'...")
7 result = func(*args, **kwargs)
8 end_time = time.time()
9 print(f"Function '{func.__name__}' completed in {end_time - start_time} seconds")
10 return result
11 return wrapper
12
13@log_time
14def long_task(duration):
15 time.sleep(duration)
16 print("Task completed!")
17
18long_task(2)
Trong ví dụ này, decorator log_time
đo thời gian thực thi của một hàm và xuất nó dưới dạng nhật ký. Hàm long_task
được bao bọc bởi decorator, và thời gian thực thi của nó được ghi lại trong quá trình chạy.
Decorator để Quản lý Quyền
Decorators cũng có thể được sử dụng để quản lý quyền. Ví dụ, bạn có thể hạn chế xử lý bằng cách kiểm tra xem người dùng có các quyền cụ thể hay không.
1def requires_permission(user_role):
2 def decorator(func):
3 def wrapper(*args, **kwargs):
4 if user_role != "admin":
5 print("Permission denied!")
6 return
7 return func(*args, **kwargs)
8 return wrapper
9 return decorator
10
11@requires_permission("admin")
12def delete_user(user_id):
13 print(f"User {user_id} has been deleted.")
14
15delete_user(123) # Executed
16delete_user = requires_permission("guest")(delete_user)
17delete_user(456) # Permission denied!
Decorator requires_permission
hạn chế việc thực thi một hàm dựa trên vai trò của người dùng. Bằng cách hợp nhất logic này vào một decorator, bạn có thể ngăn chặn logic quản lý quyền bị phân tán trong mã của mình, cải thiện khả năng đọc.
Lồng ghép Decorators
Có thể áp dụng nhiều decorators. Khi nhiều decorators được áp dụng cho một hàm, chúng sẽ được thực thi lần lượt từ trên xuống dưới.
1def uppercase(func):
2 def wrapper(*args, **kwargs):
3 result = func(*args, **kwargs)
4 return result.upper()
5 return wrapper
6
7def exclaim(func):
8 def wrapper(*args, **kwargs):
9 result = func(*args, **kwargs)
10 return result + "!"
11 return wrapper
12
13@uppercase
14@exclaim
15def greet(name):
16 return f"Hello, {name}"
17
18print(greet("Alice")) # "HELLO, ALICE!"
Trong ví dụ này, hai decorators được áp dụng cho hàm greet
. Decorator @exclaim
thêm một dấu chấm than vào cuối chuỗi, sau đó @uppercase
chuyển chuỗi thành chữ in hoa.
Decorators cho các Phương pháp của Lớp
Decorators cũng có thể được sử dụng với các phương pháp của lớp. Điều này đặc biệt hữu ích khi bạn muốn kiểm soát hành vi của các phương pháp bên trong một lớp. Khi áp dụng decorators cho các phương pháp của lớp, bạn cần chú ý đến các đối số như self
hoặc cls
.
1def log_method_call(func):
2 def wrapper(self, *args, **kwargs):
3 print(f"Calling method '{func.__name__}'...")
4 return func(self, *args, **kwargs)
5 return wrapper
6
7class MyClass:
8 @log_method_call
9 def greet(self, name):
10 print(f"Hello, {name}")
11
12obj = MyClass()
13obj.greet("Bob")
Trong ví dụ này, decorator log_method_call
được áp dụng cho phương pháp greet
để xuất nhật ký khi phương pháp được gọi.
Lưu ý khi sử dụng Decorators
Có một số điều cần cân nhắc khi sử dụng decorators. Decorators có thể thay đổi tên hàm gốc và chuỗi tài liệu (ví dụ: __name__
hoặc __doc__
), vì vậy nên sử dụng functools.wraps
để giữ lại thông tin này.
1import functools
2
3def my_decorator(func):
4 @functools.wraps(func)
5 def wrapper(*args, **kwargs):
6 print("Before the function call")
7 return func(*args, **kwargs)
8 return wrapper
Sử dụng @functools.wraps
đảm bảo rằng siêu dữ liệu của hàm gốc được truyền đúng cách đến hàm bao bọc.
Tóm tắt
Trình trang trí (decorators) trong Python là một công cụ rất mạnh mẽ, cho phép bạn bổ sung thêm chức năng cho các hàm và phương thức một cách ngắn gọn. Chúng có thể được sử dụng trong nhiều tình huống khác nhau để giảm sự trùng lặp mã và cải thiện khả năng duy trì cũng như tái sử dụng. Bằng cách hiểu cách hoạt động của trình trang trí, bạn có thể viết mã hiệu quả và linh hoạt hơn.
Bạn có thể làm theo bài viết trên bằng cách sử dụng Visual Studio Code trên kênh YouTube của chúng tôi. Vui lòng ghé thăm kênh YouTube.