CÔNG CỤ
MODULES
THAM KHẢO
Cách chia List thành các phần bằng nhau trong Python Cách xóa một khóa (key) ra khỏi dictionary trong Python Hướng dẫn chuyển đổi file Google Colab sang Markdown trong Python Bài tập Python: Lập trình cơ sở dữ liệu trong Python Kết nối cơ sở dữ liệu MySQL Python Hướng dẫn kết nối Python PostgreSQL bằng Psycopg2 Hướng dẫn kết nối SQLite sử dụng sqlite3 trong Python Bài tập Python : Pandas trong Python Phạm vi số float của Python Cách lên lịch chạy script Python bằng GitHub Actions Cách tạo hằng số trong Python Các nền tảng lưu trữ tốt nhất cho ứng dụng và script Python 6 Tip viết vòng lặp For hiệu quả hơn trong Python Cách đảo ngược Chuỗi String trong Python Cách gỡ lỗi ứng dụng Python trong Docker Container bằng VS Code 10 tip One Liner bạn cần biết trong Python Cách áp dụng ngưỡng hình ảnh trong Python với NumPy Tìm hiểu về các phép toán Groupby trong Pandas Lập trình Socket trong Python Mô-đun base64 trong Python Cách giới hạn float values trong Python Tìm hiểu Mô-đun statistics Trong Python File Organizing trong Python Đổi tên File trong Python Tìm hiểu về Deque trong Python Mô-đun Calendar trong Python Tìm hiểu về Enum trong Python Sử dụng pprint trong Python Làm việc với cấu trúc Dữ liệu Stack trong Python Thư viện functools trong Python Tip sử dụng hàm round() với tham số âm trong Python Hàm print có thể nhận thêm các tham số bổ sung trong Python Tip tìm chuỗi dài nhất bằng hàm max() trong Python Cách lặp qua nhiều list với hàm zip() trong Python Tìm hiểu về MLOps trong Python Docker và Kubernetes với MLOps trong Python Kết hợp DevOps với MLOps trong Python Xử lý độ chính xác các hàm floor, ceil, round, trunc, format trong Python tối ưu quy trình MLOps Với Python Sự khác biệt giữa byte objects và string trong Python Top 4 thư viện phổ biến nhất của NLP trong Python Cách sử dụng ThreadPoolExecutor trong Python Phân tích dữ liệu Blockchain với Python Hướng dẫn triển khai Smart Contracts với Python Blockchain APIs với Python Làm việc với file ZIP trong Python Sự khác biệt giữa toán tử == và is trong Python Chuyển đổi kiểu dữ liệu trong Python Cách làm việc với file tarball/tar trong Python Sự khác biệt giữa iterator và iterable trong Python Sự khác biệt giữa set() và frozenset() trong Python Làm việc với các biến môi trường trong Python Một tác vụ phổ biến khi làm việc với danh sách trong Python Định dạng chuỗi Strings trong Python Sử dụng Poetry để quản lý dependencies trong Python Sự khác biệt giữa sort() và sorted() trong Python Từ khóa yield trong Python Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass Cách truy cập và thiết lập biến môi trường trong Python Hướng dẫn toàn diện về module datetime trong Python Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python Quản lý sinh viên Python & MySQL
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.

Tìm hiểu về Decorator trong Python

Trong Python, decorator là một công cụ mạnh mẽ giúp mở rộng và thay đổi hành vi của các hàm hoặc phương thức mà không cần sửa đổi mã nguồn ban đầu. Việc hiểu và sử dụng decorator không chỉ giúp bạn viết mã ngắn gọn, dễ bảo trì mà còn tăng cường khả năng tái sử dụng mã. Trong bài viết này, mình sẽ tìm hiểu khái niệm decorator trong Python, tìm hiểu cách chúng hoạt động và cách bạn có thể phát triển các decorator của riêng mình để áp dụng trong các dự án thực tế.

test php

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Decorator trong Python là gì?

Một decorator là một hàm nhận một hàm khác làm đối số và mở rộng hành vi của hàm đó mà không thay đổi hàm gốc.

Hãy lấy một ví dụ đơn giản để hiểu rõ hơn khái niệm này.

Ví dụ đơn giản về decorator trong Python

Đoạn mã sau định nghĩa hàm net_price:

Bài viết này được đăng tại [free tuts .net]

def net_price(price, tax):
    """ Tính giá ròng từ giá bán và thuế
    Tham số:
        price: giá bán
        tax: thuế giá trị gia tăng hoặc thuế bán hàng
    Trả về:
        giá ròng
    """
    return price * (1 + tax)

Hàm net_price tính giá ròng từ giá bán và thuế. Nó trả về giá ròng dưới dạng một số.

Giả sử bạn cần định dạng giá ròng theo đơn vị tiền tệ USD. Ví dụ, 100 thành $100. Để làm điều này, bạn có thể sử dụng một decorator.

Theo định nghĩa, một decorator là một hàm nhận một hàm làm đối số:

def currency(fn):
    pass

Và nó trả về một hàm khác:

def currency(fn):
    def wrapper(*args, **kwargs):
        fn(*args, **kwargs)
    return wrapper

Hàm currency trả về hàm wrapper. Hàm wrapper có các tham số *args**kwargs.

Các tham số này cho phép bạn gọi bất kỳ hàm fn nào với bất kỳ sự kết hợp nào của các đối số vị trí và đối số từ khóa.

Trong ví dụ này, hàm wrapper về cơ bản thực thi hàm fn trực tiếp và không thay đổi bất kỳ hành vi nào của hàm fn.

Trong hàm wrapper, bạn có thể gọi hàm fn, lấy kết quả của nó và định dạng kết quả dưới dạng chuỗi tiền tệ:

def currency(fn):
    def wrapper(*args, **kwargs):
        result = fn(*args, **kwargs)
        return f'${result}'
    return wrapper

Hàm currency là một decorator.

Nó chấp nhận bất kỳ hàm nào trả về một số và định dạng số đó thành chuỗi tiền tệ.

Để sử dụng decorator currency, bạn cần truyền hàm net_price vào nó để nhận một hàm mới và thực thi hàm mới như thể đó là hàm gốc. Ví dụ:

net_price = currency(net_price)
print(net_price(100, 0.05))

Kết quả:

$105.0

Định nghĩa decorator trong Python

Nói chung, một decorator là:

  • Một hàm nhận một hàm khác (hàm gốc) làm đối số và trả về một hàm khác (hoặc closure).
  • Hàm closure thường chấp nhận bất kỳ sự kết hợp nào của các đối số vị trí và đối số từ khóa.
  • Hàm closure gọi hàm gốc bằng cách sử dụng các đối số được truyền vào closure và trả về kết quả của hàm.

Hàm bên trong là một closure vì nó tham chiếu đến đối số fn từ phạm vi bao quanh của nó hoặc hàm decorator.

Ký hiệu @

Trong ví dụ trước, currency là một decorator. Bạn có thể trang trí hàm net_price bằng cú pháp sau:

net_price = currency(net_price)

Thông thường, nếu decorate là một hàm decorator và bạn muốn trang trí một hàm khác fn, bạn có thể sử dụng cú pháp này:

fn = decorate(fn)

Để tiện lợi hơn, Python cung cấp một cách ngắn gọn như sau:

@decorate
def fn():
    pass

Ví dụ, thay vì sử dụng cú pháp sau:

net_price = currency(net_price)

Bạn có thể trang trí hàm net_price bằng ký hiệu @currency như sau:

@currency
def net_price(price, tax):
    """ Tính giá ròng từ giá bán và thuế
    Tham số:
        price: giá bán
        tax: thuế giá trị gia tăng hoặc thuế bán hàng
    Trả về:
        giá ròng
    """
    return price * (1 + tax)

Đặt tất cả lại với nhau.

def currency(fn):
    def wrapper(*args, **kwargs):
        result = fn(*args, **kwargs)
        return f'${result}'
    return wrapper


@currency
def net_price(price, tax):
    """ Tính giá ròng từ giá bán và thuế
    Tham số:
        price: giá bán
        tax: thuế giá trị gia tăng hoặc thuế bán hàng
    Trả về:
        giá ròng
    """
    return price * (1 + tax)


print(net_price(100, 0.05))

Tìm hiểu hàm được trang trí trong Python

Khi bạn trang trí một hàm:

@decorate
def fn(*args, **kwargs):
    pass

Nó tương đương với:

fn = decorate(fn)

Hàm decorate trả về một hàm mới, đó là hàm wrapper.

Nếu bạn sử dụng hàm tích hợp help để hiển thị tài liệu của hàm mới, bạn sẽ không thấy tài liệu của hàm gốc. Ví dụ:

help(net_price)

Kết quả:

wrapper(*args, **kwargs)
None

Ngoài ra, nếu bạn kiểm tra tên của hàm mới, Python sẽ trả về tên của hàm bên trong được trả về bởi decorator:

print(net_price.__name__)

Kết quả:

wrapper

Vì vậy, khi bạn trang trí một hàm, bạn sẽ mất chữ ký và tài liệu gốc của hàm.

Để khắc phục điều này, bạn có thể sử dụng hàm wraps từ mô-đun tiêu chuẩn functools. Thực tế, hàm wraps cũng là một decorator.

Dưới đây là cách sử dụng decorator wraps:

from functools import wraps


def currency(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        result = fn(*args, **kwargs)
        return f'${result}'
    return wrapper


@currency
def net_price(price, tax):
    """ Tính giá ròng từ giá bán và thuế
    Tham số:
        price: giá bán
        tax: thuế giá trị gia tăng hoặc thuế bán hàng
    Trả về:
        giá ròng
    """
    return price * (1 + tax)


help(net_price)
print(net_price.__name__)

Kết quả:

net_price(price, tax)
    Tính giá ròng từ giá bán và thuế
    Tham số:
        price: giá bán
        tax: thuế giá trị gia tăng hoặc thuế bán hàng
    Trả về:
        giá ròng

net_price

Kết bài

Một decorator là một công cụ hữu ích giúp thay đổi hành vi của một hàm khác mà không cần thay đổi mã nguồn của nó một cách rõ ràng. Sử dụng ký hiệu @ giúp bạn dễ dàng áp dụng decorator cho hàm. Để giữ lại tài liệu và tên của hàm gốc khi sử dụng decorator, bạn nên sử dụng hàm wraps từ mô-đun tích hợp functools. Việc hiểu và áp dụng decorator một cách hiệu quả sẽ giúp bạn viết mã Python linh hoạt, dễ bảo trì và tăng cường khả năng tái sử dụng.

Cùng chuyên mục:

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn toàn diện về module datetime trong Python

Hướng dẫn toàn diện về module datetime trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Từ khóa yield trong Python

Từ khóa yield trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Định dạng chuỗi Strings trong Python

Định dạng chuỗi Strings trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Làm việc với các biến môi trường trong Python

Làm việc với các biến môi trường trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa iterator và iterable trong Python

Sự khác biệt giữa iterator và iterable trong Python

Cách làm việc với file tarball/tar trong Python

Cách làm việc với file tarball/tar trong Python

Chuyển đổi kiểu dữ liệu trong Python

Chuyển đổi kiểu dữ liệu trong Python

Sự khác biệt giữa toán tử == và is trong Python

Sự khác biệt giữa toán tử == và is trong Python

Làm việc với file ZIP trong Python

Làm việc với file ZIP trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Sự khác biệt giữa byte objects và string trong Python

Sự khác biệt giữa byte objects và string trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format  trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Top