DECORATORS Python: Thêm Siêu Năng Lực Cho Hàm Của Bạn

Xin chào bạn, những người lập trình Python đầy kí niệm! Hôm nay, chúng ta sẽ bơi lội vào thế giới thú vị của Decorators Python. Hãy tưởng tượng Decorators như những bọc bìa kỳ diệu có thể nâng cấp hàm của bạn với siêu năng lực. Thú vị phải không? Hãy cùng nhau bắt đầu hành trình này!

Python - Decorators

Decorators Là Gì?

Tưởng tượng bạn có một món quà được trang trí đẹp mắt. Giấy bọc không thay đổi quà bên trong, nhưng nó làm cho quà trông xinh hơn, phải không? Đó chính xác là điều gì Decorators làm cho hàm của bạn trong Python. Chúng bọc quanh hàm của bạn, thêm chức năng bổ sung mà không thay đổi hàm gốc của nó.

Hãy bắt đầu với một ví dụ đơn giản:

def my_decorator(func):
def wrapper():
print("Đang có điều gì đó xảy ra trước khi gọi hàm.")
func()
print("Đang có điều gì đó xảy ra sau khi gọi hàm.")
return wrapper

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

say_hello()

Nếu bạn chạy mã này, bạn sẽ thấy:

Đang có điều gì đó xảy ra trước khi gọi hàm.
Hello!
Đang có điều gì đó xảy ra sau khi gọi hàm.

Hãy phân tích:

  1. Chúng ta định nghĩa một hàm trang trí my_decorator nhận một hàm làm đối số.
  2. Trong my_decorator, chúng ta định nghĩa một hàm wrapper thêm một số hành vi trước và sau khi gọi hàm gốc.
  3. Chúng ta sử dụng cú pháp @my_decorator để áp dụng trang trí của mình cho hàm say_hello.
  4. Khi chúng ta gọi say_hello(), thực chất là nó đang gọi phiên bản bọc của hàm.

Điều đó thật tuyệt vời phải không? Chúng ta vừa thêm một số hành vi bổ sung vào hàm say_hello của mình mà không cần sửa mã của nó!

Decorators Với Đối Số

Nhưng chờ chút, còn nhiều hơn nữa! Như thế nào nếu hàm của chúng ta nhận đối số? Không có vấn đề! Chúng ta có thể điều chỉnh trang trí của mình để xử lý điều đó:

def my_decorator(func):
def wrapper(*args, **kwargs):
print("Trước khi gọi hàm.")
result = func(*args, **kwargs)
print("Sau khi gọi hàm.")
return result
return wrapper

@my_decorator
def add(a, b):
return a + b

print(add(3, 5))

Điều này sẽ đầu ra:

Trước khi gọi hàm.
Sau khi gọi hàm.
8

Ở đây, *args**kwargs cho phép trang trí của chúng ta hoạt động với bất kỳ số lượng đối số vị trí và từ khóa nào.

Trang Trí Độc Lập

Python đi kèm với một số trang trí độc lập rất hữu ích. Hãy khám phá chúng!

Trang Trí @classmethod

Trang trí @classmethod được sử dụng để định nghĩa các phương thức hoạt động trên lớp chính, thay vì các thể hiện của lớp.

class Pizza:
def __init__(self, ingredients):
self.ingredients = ingredients

@classmethod
def margherita(cls):
return cls(['mozzarella', 'cà chua'])

@classmethod
def prosciutto(cls):
return cls(['mozzarella', 'cà chua', 'thịt giăm bông'])

print(Pizza.margherita().ingredients)
print(Pizza.prosciutto().ingredients)

Điều này sẽ đầu ra:

['mozzarella', 'cà chua']
['mozzarella', 'cà chua', 'thịt giăm bông']

Ở đây, margheritaprosciutto là các phương thức lớp để tạo và trả lại các thể hiện mới của Pizza với các nguyên liệu xác định sẵn.

Trang Trí @staticmethod

Các phương thức tĩnh là các phương thức không hoạt động trên thể hiện hoặc lớp. Chúng chỉ là các hàm bình thường xảy ra trong một lớp.

class Math:
@staticmethod
def add(a, b):
return a + b

print(Math.add(5, 10))

Điều này sẽ đầu ra:

15

Trang Trí @property

Trang trí @property cho phép bạn định nghĩa các phương thức mà bạn có thể truy cập như các thuộc tính.

class Circle:
def __init__(self, radius):
self._radius = radius

@property
def radius(self):
return self._radius

@property
def area(self):
return 3.14 * self._radius ** 2

c = Circle(5)
print(c.radius)
print(c.area)

Điều này sẽ đầu ra:

5
78.5

Ở đây, chúng ta có thể truy cập radiusarea như là các thuộc tính, nhưng chúng thực chất là các phương thức.

Trang Trí @functools.wraps

Trang trí này được sử dụng để bảo tồn metadata của hàm gốc khi tạo các trang trí.

from functools import wraps

def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Đây là hàm bọc"""
return func(*args, **kwargs)
return wrapper

@my_decorator
def my_function():
"""Đây là hàm của tôi"""
pass

print(my_function.__name__)
print(my_function.__doc__)

Điều này sẽ đầu ra:

my_function
Đây là hàm của tôi

Nếu không có @wraps, tên hàm và chuỗi tài liệu sẽ là của hàm bọc.

Kết Luận

Các trang trí là một tính năng mạnh mẽ trong Python cho phép bạn sửa đổi hoặc nâng cấp các hàm và phương thức. Chúng được sử dụng rộng rãi trong các khung công tác và thư viện để thêm chức năng như ghi nhật ký, kiểm soát truy cập, và nhiều hơn nữa.

Hãy nhớ, chìa khóa để nắm vững các trang trí là thực hành. Hãy thử tạo các trang trí của riêng bạn và áp dụng chúng cho các hàm khác nhau. Ngay lập tức, bạn sẽ bọc hàm của mình với siêu năng lực như một chuyên gia!

Dưới đây là bảng tóm tắt các trang trí mà chúng ta đã trình bày:

Trang Trí Mục Đích
@classmethod Định nghĩa các phương thức hoạt động trên lớp chính
@staticmethod Định nghĩa các phương thức không hoạt động trên thể hiện hoặc lớp
@property Định nghĩa các phương thức có thể truy cập như các thuộc tính
@functools.wraps Bảo tồn metadata của hàm gốc trong các trang trí

Chúc bạn mãi mãi có các hàm luôn được trang trí đẹp mắt!

Credits: Image by storyset