Python enumeration (Enum) usage tutorial

enumerate(Enum) is the built-in standard library of Python 3.4+, which is specially used to define named constants with clear semantics, unmodifiable, and limited values. And the traditional way of expressing constants by capitalizing variables (such asMONTH_JAN = 1), enumerations can provide:

  • Static Safety: Avoid typing wrong variable names or passing in illegal values;
  • Clear Semantics: Enhance code readability;
  • Normalized access and traversal: unified access through member names or values, and supports traversal of all members;
  • Business logic cohesion: Constant-related logic can be directly encapsulated in enumeration classes.

In production-level code, proper use of enumerations can significantly improve the robustness and maintainability of the code.


1. Basic enumeration definition

Python provides two ways to create enumerations: quick factory functions, and more flexible custom subclasses.

Method 1: Quickly create factory functions

Suitable for applications that require only a set of sequentially increasing default values ​​(from1start) scene:

from enum import Enum

# 参数1:枚举类名
# 参数2:枚举成员的元组(也支持空格分隔的字符串、名称-值字典等)
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                       'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

The enumeration members generated in this way have two fixed properties:

  • name:String name of the member, for exampleMonth.Jan.namefor'Jan'
  • value: The automatically assigned value of the member, e.g.Month.Jan.valuefor1

Applicable scenarios: Simple, temporary constant grouping, no custom values ​​or additional methods required.


inheritEnumBase classes can define more flexible and readable enumerations, while strengthening constraints through decorators and custom behaviors.

from enum import Enum, unique

# @unique 装饰器强制所有成员的 value 唯一,出现重复会直接报错
@unique
class Weekday(Enum):
    Sun = 0    # 自定义初始值
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

**@uniqueFunction: ** In regular development, this decorator should always be added to enumeration classes to prevent inadvertent duplication of values, which may lead to logical confusion.


2. Access methods of enumeration members

Enumeration members cannot be used directly==Compares to integer strings (unless usingIntEnumand other special subcategories), it is recommended to use the following four normalization methods:

# 1. 点号访问(最常用)
day1 = Weekday.Mon
print(day1)                # 输出:Weekday.Mon

# 2. 通过成员名称访问(适用于动态场景)
print(Weekday['Tue'])      # 输出:Weekday.Tue

# 3. 通过成员值访问(反向解析)
print(Weekday(1))          # 输出:Weekday.Mon
# 如果值不存在,会抛出 ValueError,适合用来校验传入值

# 4. 枚举成员之间直接比较(安全可靠)
print(day1 == Weekday.Mon) # True
print(day1 == Weekday.Tue) # False

Tip: Use it directlyWeekday(1)When obtaining enumeration members, if the incoming value is invalid, an exception will be thrown immediately. This is safer than using integer comparison and can quickly locate illegal data.


3. Practical advanced features

3.1 Automatic assignment (auto()

You can use it when the enumeration value itself is not important and is just used to distinguish different members.auto()Automatically assign consecutive values ​​(default from1start):

from enum import Enum, auto

class Color(Enum):
    RED   = auto()   # value=1
    GREEN = auto()   # value=2
    BLUE  = auto()   # value=3

auto()Different default values ​​may be generated in different enumeration base classes (such asIntFlagwill be generated bit by bit), please refer to the official documentation for details.


3.2 Customize member values ​​and bind additional properties/methods

enumeration membersvalueCan be of any type (tuple, list, object, etc.), and enumeration classes can be defined like ordinary classes__init__and instance methods to achieve encapsulation of data and behavior.

from enum import Enum

class Planet(Enum):
    # 每个成员的 value 是一个元组,会作为参数传递给 __init__
    EARTH = (5.97e24, 6371)   # 质量(kg)、半径(km)
    MARS  = (6.39e23, 3389)

    # 自动解析 value 并绑定到实例属性
    def __init__(self, mass, radius):
        self.mass = mass
        self.radius = radius

    # 将计算逻辑直接放在枚举类中,提高内聚性
    @property
    def surface_gravity(self):
        G = 6.673e-11
        return G * self.mass / (self.radius * 1000) ** 2

# 使用
print(Planet.EARTH.surface_gravity)   # 约 9.81(地球表面重力)
print(Planet.MARS.value)              # (6.39e23, 3389)

Design Idea: Placing business logic closely related to constants (such as calculations and state flow rules) inside the enumeration class can effectively prevent logic from being scattered throughout the code and improve maintainability.


3.3 Traverse all enumeration members

pass__members__Attributes can obtain the mapping from member names to members to facilitate traversal and display:

for name, member in Weekday.__members__.items():
    print(f"{name} -> {member} ,数值 = {member.value}")

If used@uniquedecorator,__members__There will be no aliases generated by duplicate values, and the traversal results will be cleaner.


4. Practical application example: gender enumeration

Traditional code may use0/1/2Indicates gender, which is poorly readable and easily mistransmitted. Using enumerations can completely solve this problem:

from enum import Enum, unique

@unique
class Gender(Enum):
    MALE   = 0
    FEMALE = 1
    OTHER  = 2

class Student:
    def __init__(self, name, gender):
        self.name = name
        # 强制要求参数为 Gender 枚举成员
        if not isinstance(gender, Gender):
            raise ValueError("gender 必须是 Gender 枚举的成员")
        self.gender = gender

    def __repr__(self):
        # 输出时使用 .name 提高可读性
        return f"Student(name={self.name}, gender={self.gender.name})"

# 正确使用
student = Student("Alice", Gender.FEMALE)
print(student)   # Student(name=Alice, gender=FEMALE)

# 错误使用会立即抛出异常
try:
    invalid_student = Student("Bob", 1)   # 传入整数而不是枚举成员
except ValueError as e:
    print(e)     # gender 必须是 Gender 枚举的成员

Summary of advantages:

  • Type Safety: Limit parameter types during the value transfer stage to avoid1andGender.MALEmisuse.
  • Easy to read and use: in the codeGender.FEMALECompare1More expressive.
  • Extensible: When expanding gender categories in the future, you only need to modify the enumeration class, and the caller does not need to look for the meaning of the number everywhere.

5. Convenience subclasses for Python 3.11+

If the enumeration value ** must be a native string or integer ** and needs to be directly compatible with the original type (such asLogLevel.INFO == "info"returnTrue), you can use the new ones added in Python 3.11StrEnumIntEnumIntFlagand other subcategories.

from enum import StrEnum, IntEnum

# StrEnum:value 自动为字符串,且可以直接与字符串相等比较
class LogLevel(StrEnum):
    DEBUG   = "debug"
    INFO    = "info"
    WARNING = "warning"

print(LogLevel.INFO == "info")   # True (普通 Enum 做不到)

# IntEnum:value 自动为整数,且可以直接与整数相等比较
class StatusCode(IntEnum):
    OK        = 200
    NOT_FOUND = 404

print(StatusCode.OK == 200)      # True

NOTE:StrEnumandIntEnumAlthough it brings the convenience of compatibility, it may also weaken type checking, requiring a trade-off between convenience and security.


6. Summary of best practices

  1. Always add@uniqueDecorator Prevent duplicate values ​​from appearing in the same enumeration class and avoid hidden bugs.
  2. Prefer using custom subclasses instead of factory functions The subclass method is easier to expand, document, and can bind business logic.
  3. Avoid using values ​​directly for equality comparison Unless usingStrEnum / IntEnum, otherwise the correct way is to use the enumeration members themselves for comparison.
  4. Encapsulate relevant logic into enumeration classes as beforePlanet.surface_gravity, improve cohesion and reduce external logic scatter.
  5. Follow naming conventions Use camelCase for enumeration class names (such asWeekday), use all capital letters for member names (e.g.MONDAY), compliant with PEP 8 and community practices.

7. Summary

Python enumerations solve three core pain points in traditional constant definitions:

  • Lack of semantic safety: An error is often not reported immediately when a variable name is mistyped or an illegal value is passed in.
  • Fuzzy value boundaries: The caller does not know what values ​​the constant can take
  • Business logic is scattered: calculations and rules related to constants are scattered in various modules

By introducingEnumand its subclasses, the code can not only achieve stronger security, readability and maintainability, but also naturally bind constant "data" and "behavior" together, in line with the principles of object-oriented design. Although the functions of Python enumerations are not as rich as those of some statically typed languages ​​(such as Java), they can already meet the vast majority of production scenarios and are a powerful helper for writing high-quality Python code.