INTRODUCTION
FLOW CONTROL
FUNCTIONS
DATATYPES
OBJECT & CLASS
Bài tập Python: Lập trình hướng đối tượng (OOP) trong Python Lập trình hướng đối tượng trong Python Class Variables trong Python Tìm hiểu về Methods trong Python Cách sử dụng phương thức __init__() trong Python Các biến Instance trong Python Tìm hiểu về Class Attributes trong Python Hàm Static Methods trong Python Phương thức __str__ trong Python Phương thức __repr__ trong Python Phương thức eq trong Python Tìm hiểu phương thức __hash__ trong Python Phương thức __bool__ trong Python Phương thức del trong Python Tìm hiểu về lớp Property trong Python Tìm hiểu về nạp chồng toán tử trong Python Trình Decorator Property trong Python Thuộc tính chỉ đọc trong Python Thuộc tính Delete trong Python Sử dụng super() trong Python Sử dụng __slots__ trong Python Cách sử dụng Protocol trong Python Sử dụng Enum aliases và @enum.unique trong Python Tùy chỉnh và mở rộng lớp Enum trong Python Cách sử dụng hàm Auto() của Python Single Responsibility Principle trong Python Nguyên tắc Đóng-Mở trong Python Nguyên tắc thay thế Liskov - LSP trong Python Interface Segregation Principle - ISP trong Python. Nguyên tắc đảo ngược sự phụ thuộc trong Python Đa kế thừa trong Python Tìm hiểu về các lớp mixin trong Python Mô tả Descriptors trong Python Phân biệt Data Descriptor và Non-data Descriptor trong Python Phương thức __new__ trong Python Tìm hiểu về Class Type trong Python Lớp Metaclass trong Python Ví dụ sử dụng metaclass trong Python Tìm hiểu về decorator dataclass trong Python Tìm hiểu về các ngoại lệ trong Python Ngoại lệ Raise trong Python Sử dụng câu lệnh raise from trong Python Ngoại lệ tùy chỉnh trong Python Module trong Python Package trong Python Class trong Python Hàm khởi tạo trong Python Kế thừa trong Python Đa kế thừa trong Python Setter và Getter trong Python Override trong Python Interface trong Python Bài tập Python: Module và Class
ADVANCED TOPICS
BỔ SUNG
PYTHON CĂN BẢN
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ùy chỉnh và mở rộng lớp Enum trong Python

Trong bài viết này, mình sẽ tìm hiểu cách tùy chỉnh và mở rộng các lớp Enum (liệt kê) trong Python. Python Enum không chỉ đơn thuần là một danh sách các hằng số, mà chúng còn là những lớp có thể được mở rộng và tùy chỉnh với các phương thức đặc biệt (dunder methods) để tạo ra những hành vi riêng biệt. Qua việc triển khai các phương thức như __str__, __eq__, và __lt__, bạn có thể thay đổi cách các giá trị Enum được so sánh, sắp xếp hoặc hiển thị, giúp tăng cường tính linh hoạt và sức mạnh của các lớp liệt kê trong Python.

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.

Tùy chỉnh lớp Enum trong Python

Các liệt kê (enumerations) trong Python thực chất là các lớp (classes). Điều này có nghĩa là bạn có thể thêm các phương thức (methods) vào chúng hoặc triển khai các phương thức đặc biệt (dunder methods) để tùy chỉnh hành vi của chúng.

Ví dụ sau định nghĩa lớp liệt kê PaymentStatus:

from enum import Enum

class PaymentStatus(Enum):
    PENDING = 1
    COMPLETED = 2
    REFUNDED = 3

Lớp PaymentStatus có ba thành viên: PENDING, COMPLETED, và REFUNDED.

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

Nếu bạn hiển thị thành viên PENDING:

print(PaymentStatus.PENDING)

Kết quả sẽ là:

PaymentStatus.PENDING

Tùy chỉnh hiển thị chuỗi

Bạn có thể tùy chỉnh cách hiển thị chuỗi của các thành viên trong liệt kê bằng cách triển khai phương thức __str__. Ví dụ:

from enum import Enum

class PaymentStatus(Enum):
    PENDING = 1
    COMPLETED = 2
    REFUNDED = 3

    def __str__(self):
        return f'{self.name.lower()}({self.value})'

print(PaymentStatus.PENDING)

Kết quả sẽ là:

pending(1)

Triển khai phương thức __eq__

Khi so sánh thành viên của PaymentStatus với một số nguyên, ví dụ như:

if PaymentStatus.PENDING == 1:
    print('The payment is pending.')

Sẽ không có gì được in ra, vì PaymentStatus.PENDING không bằng với số nguyên 1.

Để so sánh các thành viên của PaymentStatus với số nguyên, bạn có thể triển khai phương thức __eq__ như sau:

from enum import Enum

class PaymentStatus(Enum):
    PENDING = 1
    COMPLETED = 2
    REFUNDED = 3

    def __str__(self):
        return f'{self.name.lower()}({self.value})'

    def __eq__(self, other):
        if isinstance(other, int):
            return self.value == other
        if isinstance(other, PaymentStatus):
            return self is other
        return False

if PaymentStatus.PENDING == 1:
    print('The payment is pending.')

Trong phương thức __eq__:

  • Nếu giá trị so sánh là số nguyên, nó sẽ so sánh giá trị của thành viên với số nguyên.
  • Nếu giá trị so sánh là một thể hiện của PaymentStatus, nó sẽ so sánh giá trị với thành viên bằng toán tử is.
  • Nếu không, nó sẽ trả về False.

Kết quả của đoạn mã trên sẽ là:

The payment is pending.

Triển khai phương thức __lt__

Giả sử bạn muốn các thành viên của PaymentStatus có thứ tự sắp xếp dựa trên giá trị của chúng, và bạn cũng muốn so sánh chúng với một số nguyên.

Bạn có thể triển khai phương thức __lt__ và sử dụng decorator @total_ordering từ module functools:

from enum import Enum
from functools import total_ordering

@total_ordering
class PaymentStatus(Enum):
    PENDING = 1
    COMPLETED = 2
    REFUNDED = 3

    def __str__(self):
        return f'{self.name.lower()}({self.value})'

    def __eq__(self, other):
        if isinstance(other, int):
            return self.value == other
        if isinstance(other, PaymentStatus):
            return self is other
        return False

    def __lt__(self, other):
        if isinstance(other, int):
            return self.value < other
        if isinstance(other, PaymentStatus):
            return self.value < other.value
        return False

# So sánh với một số nguyên
status = 1
if status < PaymentStatus.COMPLETED:
    print('The payment has not completed.')

# So sánh với một thành viên khác
status = PaymentStatus.PENDING
if status >= PaymentStatus.COMPLETED:
    print('The payment is not pending.')

Triển khai phương thức __bool__

Mặc định, tất cả các thành viên của liệt kê đều có giá trị là True. Ví dụ:

for member in PaymentStatus:
    print(member, bool(member))

Nếu bạn muốn thay đổi hành vi này, bạn có thể triển khai phương thức __bool__. Giả sử bạn muốn các thành viên COMPLETEDREFUNDED có giá trị True, còn PENDINGFalse. Đoạn mã sau minh họa cách làm điều này:

from enum import Enum
from functools import total_ordering

@total_ordering
class PaymentStatus(Enum):
    PENDING = 1
    COMPLETED = 2
    REFUNDED = 3

    def __str__(self):
        return f'{self.name.lower()}({self.value})'

    def __eq__(self, other):
        if isinstance(other, int):
            return self.value == other
        if isinstance(other, PaymentStatus):
            return self is other
        return False

    def __lt__(self, other):
        if isinstance(other, int):
            return self.value < other
        if isinstance(other, PaymentStatus):
            return self.value < other.value
        return False

    def __bool__(self):
        if self is self.COMPLETED:
            return True
        return False

for member in PaymentStatus:
    print(member, bool(member))

Kết quả sẽ là:

pending(1) False
completed(2) True
refunded(3) False

Mở rộng lớp Enum trong Python

Python không cho phép mở rộng một lớp Enum nếu nó đã có các thành viên. Tuy nhiên, điều này không phải là một hạn chế thực sự. Bạn có thể định nghĩa một lớp cơ bản (base class) có phương thức nhưng không có thành viên, sau đó mở rộng lớp cơ bản này.

Ví dụ, đầu tiên, định nghĩa lớp cơ bản OrderedEnum để sắp xếp các thành viên theo giá trị:

from enum import Enum
from functools import total_ordering

@total_ordering
class OrderedEnum(Enum):
    def __lt__(self, other):
        if isinstance(other, OrderedEnum):
            return self.value < other.value
        return NotImplemented

Sau đó, định nghĩa lớp ApprovalStatus kế thừa từ OrderedEnum:

class ApprovalStatus(OrderedEnum):
    PENDING = 1
    IN_PROGRESS = 2
    APPROVED = 3

Cuối cùng, bạn có thể so sánh các thành viên của lớp ApprovalStatus:

status = ApprovalStatus(2)
if status < ApprovalStatus.APPROVED:
    print('The request has not been approved.')

Kết quả sẽ là:

The request has not been approved.

Kết bài

Việc triển khai các phương thức đặc biệt cho phép chúng ta tùy chỉnh hành vi của các lớp Enum trong Python, từ đó có thể dễ dàng quản lý và thao tác với các thành viên trong lớp liệt kê theo cách phù hợp với yêu cầu cụ thể của dự án. Ngoài ra, bằng cách định nghĩa một lớp Enum cơ bản không có thành viên và phương thức, chúng ta có thể mở rộng lớp này để tạo ra nhiều lớp Enum khác nhau, tận dụng lại các phương thức tùy chỉnh đã được định nghĩa. Cách tiếp cận này giúp mã nguồn trở nên linh hoạt, dễ bảo trì và tiết kiệm thời gian khi làm việc với các Enum có yêu cầu phức tạp.

Cùng chuyên mục:

Cách tạo thư mục lồng nhau (nested directory) trong Python

Cách tạo thư mục lồng nhau (nested directory) trong Python

Cách thêm số 0 vào đầu chuỗi trong Python

Cách thêm số 0 vào đầu chuỗi trong Python

Sự khác biệt giữa @classmethod, @staticmethod và instance methods trong Python

Sự khác biệt giữa @classmethod, @staticmethod và instance methods trong Python

Sự khác biệt giữa str và repr trong Python

Sự khác biệt giữa str và repr trong Python

Các cách nối hai danh sách trong Python

Các cách nối hai danh sách trong Python

Sự khác biệt giữa append() và extend() trong list Python

Sự khác biệt giữa append() và extend() trong list Python

5 lỗi thường gặp trong Python

5 lỗi thường gặp trong Python

Các tính năng mới trong Python 3.10

Các tính năng mới trong Python 3.10

Tạo app ghi chú trong Python với nhận dạng giọng nói và API Notion

Tạo app ghi chú trong Python với nhận dạng giọng nói và API Notion

Làm chủ Pattern Matching trong Python 3.10

Làm chủ Pattern Matching trong Python 3.10

Cách yêu cầu người dùng nhập liệu đến khi nhận được phản hồi hợp lệ trong Python

Cách yêu cầu người dùng nhập liệu đến khi nhận được phản hồi hợp lệ trong Python

8 Mẹo Refactor Code Python nhanh gọn (Phần 2)

8 Mẹo Refactor Code Python nhanh gọn (Phần 2)

Cách sao chép file trong Python

Cách sao chép file trong Python

31 Phương thức xử lý chuỗi (String) quan trọng trong Python

31 Phương thức xử lý chuỗi (String) quan trọng trong Python

Cách xóa file và thư mục trong Python

Cách xóa file và thư mục trong Python

Tìm hiểu về *args và **kwargs trong Python

Tìm hiểu về *args và **kwargs trong Python

Cách làm phẳng danh sách lồng nhau trong Python

Cách làm phẳng danh sách lồng nhau trong Python

Phân tích dữ liệu Apple Health bằng Python

Phân tích dữ liệu Apple Health bằng Python

Cách loại bỏ phần tử trùng lặp khỏi danh sách (List) trong Python

Cách loại bỏ phần tử trùng lặp khỏi danh sách (List) trong Python

Cách cắt (slicing) chuỗi trong Python

Cách cắt (slicing) chuỗi trong Python

Top