← 返回题目列表

Python 的 enum 枚举怎么用?和用常量、字符串有什么区别?

中等 第 17 / 21 题 更新于 2026/07/31
Pythonenum枚举IntEnum

简化版

**enum.Enum 是 Python 的「枚举」——把一组「有限的、命名的常量」定义成一个类,每个成员既有「名字(name)」又有「值(value)」,比裸用整数/字符串常量更安全、更可读、更不易出错。**用法:继承 Enum,把成员写成类属性:class Color(Enum): RED = 1; GREEN = 2; BLUE = 3,然后 Color.RED(成员)、Color.RED.name(‘RED’)、Color.RED.value(1)。相比裸常量的好处:① 类型安全——Color.RED 是一个独立的枚举成员,不会和别的整数/字符串意外相等或混用(Color.RED == 1 为 False,而裸常量 RED = 1 就等于任意的 1);② 可读——打印是 Color.RED 而非无意义的 1;③ 成员唯一、可迭代for c in Color)、可用 in 判断能当字典键;④ 防止无效值Color(5) 抛 ValueError)。常用变体IntEnum(成员也是 int、能和整数比较运算,兼容旧接口)、StrEnum(3.11+,成员也是 str)、Flag/IntFlag(位标志、可 | 组合)、auto()(自动赋值)。核心记忆:Enum 把命名常量组织成类(有 name/value、类型安全、可迭代、成员唯一),比裸常量安全可读;要和 int/str 兼容用 IntEnum/StrEnum,位标志用 Flag。

详细版

Enum 的用法

特性说明
class C(Enum): A = 1定义枚举
C.A成员(不是值)
C.A.name / C.A.value名字 ‘A’ / 值 1
C(1) / C['A']按值 / 按名查找成员
for m in C可迭代(按定义顺序)
auto()自动赋值(1, 2, 3…)
IntEnum / StrEnum成员兼是 int / str
Flag / IntFlag位标志(可 | 组合)
from enum import Enum, IntEnum, Flag, auto

# 基本枚举
class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

print(Color.RED)            # Color.RED(可读)
print(Color.RED.name)       # 'RED'
print(Color.RED.value)      # 1
print(Color(1))             # Color.RED(按值查找)
print(Color['RED'])         # Color.RED(按名查找)

# 类型安全:不会和裸整数混
print(Color.RED == 1)       # False(枚举成员 != 整数)
print(Color.RED == Color.RED)   # True(身份唯一)

# 可迭代、in 判断、当字典键
for c in Color:
    print(c.name, c.value)  # RED 1 / GREEN 2 / BLUE 3
print(Color.RED in Color)   # True
d = {Color.RED: "红色"}     # 能当字典键

# 无效值报错
# Color(5)                  # ✗ ValueError(防止无效值)

# auto() 自动赋值
class Status(Enum):
    PENDING = auto()        # 1
    RUNNING = auto()        # 2
    DONE = auto()           # 3

# IntEnum:成员也是 int,能和整数比较/运算
class Priority(IntEnum):
    LOW = 1
    HIGH = 10
print(Priority.HIGH > Priority.LOW)   # True
print(Priority.HIGH == 10)            # True(IntEnum 和 int 相等)
print(Priority.LOW + 5)               # 6(能参与运算)

# Flag:位标志,可组合
class Perm(Flag):
    READ = auto()           # 1
    WRITE = auto()          # 2
    EXEC = auto()           # 4
rw = Perm.READ | Perm.WRITE
print(Perm.READ in rw)      # True

⚠️ 核心价值:枚举把「散落的魔法常量」收拢成一个「有类型、有名字、成员唯一」的集合,用 Color.RED 代替裸的 1"red",从而获得类型安全(不会误传别的值)、可读性(打印/调试看得懂)、和一组内建能力(迭代、成员判断、防无效值)。裸常量的问题很实际:STATUS_ACTIVE = 1STATUS_DELETED = 2 散落在代码里,函数收到个 2 你不知道它是状态、优先级还是别的;传错值(set_status(5))也没人拦;打印日志看到 1 一头雾水。枚举一次解决:Status.ACTIVE 自解释、Status(5) 直接 ValueError、for s in Status 能遍历所有合法值。关键取舍是「要不要和 int/str 兼容」:Enum 最安全(成员不等于任何 int/str,Color.RED != 1),但和需要「原始值」的旧接口(数据库存整数、JSON 传字符串)对接麻烦;这时用 IntEnum(成员就是 int、能直接比较运算和序列化)或 StrEnum(3.11+,成员就是 str),牺牲一点安全换兼容性。位标志(可读写权限组合)用 Flag/IntFlag

完整版教学

一、为什么需要枚举

先理解裸常量的问题、枚举解决什么:

裸常量的问题:
  # 用模块级常量表示状态
  STATUS_PENDING = 1
  STATUS_ACTIVE = 2
  STATUS_DELETED = 3

  痛点:
  ① 没有类型——函数收到 2,不知是状态/优先级/其他
     def process(status): ...  # status 就是个 int,能传任何数
  ② 无效值不拦——process(99) 照样跑(99 没意义)
  ③ 可读性差——日志/调试看到 2,不知含义
  ④ 散落——常量分散,没有"这是一组"的归属
  ⑤ 易混——STATUS_ACTIVE=2 和 PRIORITY_HIGH=2 意外相等

枚举的解决:
  from enum import Enum
  class Status(Enum):
      PENDING = 1
      ACTIVE = 2
      DELETED = 3

  ✓ 有类型:Status.ACTIVE 是 Status 类型
  ✓ 防无效:Status(99) → ValueError
  ✓ 可读:打印 Status.ACTIVE(自解释)
  ✓ 归组:一个类装一组相关常量
  ✓ 不混:Status.ACTIVE != Priority.HIGH(不同枚举不相等)
  ✓ 附加能力:迭代、成员判断、当字典键

所以枚举解决裸常量的:无类型/无效值不拦/不可读/散落/易混,提供类型安全的命名常量组

裸常量的问题:模块级常量 STATUS_PENDING = 1 等——痛点是① 没有类型(函数收到 2 不知是状态还是别的)、② 无效值不拦(process(99) 照样跑)、③ 可读性差(日志看到 2 不知含义)、④ 散落(没有「这是一组」的归属)、⑤ 易混(STATUS_ACTIVE=2PRIORITY_HIGH=2 意外相等)枚举的解决class Status(Enum): PENDING = 1; ...——✓ 有类型(Status.ACTIVE 是 Status 类型)、✓ 防无效(Status(99) ValueError)、✓ 可读(打印 Status.ACTIVE 自解释)、✓ 归组、✓ 不混(不同枚举不相等)、✓ 附加能力(迭代/成员判断/当字典键)。理解「裸常量问题:无类型/无效值不拦/不可读/散落/易混;枚举提供类型安全的命名常量组(有类型+防无效+可读+归组+不混+附加能力)」,就理解了为什么需要枚举。

二、Enum 的基本用法

理解定义和访问枚举:

定义枚举:继承 Enum,成员作类属性
  from enum import Enum
  class Color(Enum):
      RED = 1
      GREEN = 2
      BLUE = 3

成员的三个属性:
  Color.RED         # 成员本身(Color.RED)
  Color.RED.name    # 名字 'RED'(字符串)
  Color.RED.value   # 值 1

两种查找方式:
  Color(1)          # 按"值"查找 → Color.RED
  Color['RED']      # 按"名字"查找 → Color.RED
  → 值查找用于反序列化(存的是值,还原成成员)

成员是"单例"(唯一):
  Color.RED is Color.RED    # True(每个成员全局唯一)
  Color(1) is Color.RED     # True(值查找返回同一个成员)
  → 可以放心用 is 比较

迭代(按定义顺序):
  for c in Color:
      print(c)      # Color.RED, Color.GREEN, Color.BLUE
  list(Color)       # [Color.RED, ...]

成员判断:
  Color.RED in Color        # True
  1 in Color                # False(值不是成员,注意)
  Color(1) in Color         # True

当字典键(成员可哈希):
  colors = {Color.RED: "红", Color.GREEN: "绿"}

所以定义继承 Enum、成员作类属性;.name/.value 取名和值;C(值)/C['名']查找;成员唯一可 is

定义枚举:继承 Enum、成员作类属性class Color(Enum): RED = 1; ...)。成员的三个属性Color.RED(成员本身)、Color.RED.name(名字 ‘RED’)、Color.RED.value(值 1)。两种查找方式Color(1)(按值查找)、Color['RED'](按名字查找)——值查找用于反序列化(存的是值、还原成成员)。成员是「单例」(唯一)Color.RED is Color.RED 为 True、Color(1) is Color.RED 为 True(可放心用 is 比较)。迭代(按定义顺序)for c in Color成员判断Color.RED in Color 为 True、1 in Color 为 False(值不是成员)。当字典键(成员可哈希)。理解「定义继承 Enum、成员作类属性;.name 名/.value 值;C(值)按值、C[‘名’]按名查找;成员唯一(is 比较)、可迭代(按定义顺序)、可当字典键」,就掌握了基本用法。

三、类型安全——纯 Enum 不等于 int/str

理解纯 Enum 的类型隔离:

纯 Enum 的类型安全:成员不等于任何 int/str

  class Color(Enum):
      RED = 1

  Color.RED == 1          # False!(成员 != 它的值)
  Color.RED == Color.RED  # True(同一成员)
  Color.RED.value == 1    # True(要比值用 .value)

  → 纯 Enum 成员是"独立的对象",和它的原始值不相等
  → 这是安全特性:防止枚举和裸数字/字符串混用

好处:
  ① 传参不会误用别的值
     def paint(c: Color): ...
     paint(1)          # 类型检查器(mypy)会警告
     paint(Color.RED)  # 正确
  ② 不同枚举不相等
     Color.RED == Size.SMALL   # False(即使 value 都是 1)

代价:和需要"原始值"的接口对接麻烦
  存数据库/发 JSON 时需要 .value:
    db.save(status.value)      # 存整数
    json.dumps(status.value)   # 序列化值
  从数据库/JSON 还原时用值查找:
    status = Status(db_value)
  → 纯 Enum 不能直接当 int/str 用(要手动 .value)

跨枚举比较:
  两个不同 Enum 的成员永远不相等(即使值一样)
  → 这正是"防混用"的价值

所以纯 Enum 成员!=其 value(类型安全防混用),对接原始值接口要手动.value

纯 Enum 的类型安全:成员不等于任何 int/str——Color.RED == 1 为 False(成员 != 它的值)、Color.RED == Color.RED 为 True、Color.RED.value == 1 为 True(要比值用 .value)。纯 Enum 成员是「独立的对象」、和原始值不相等(防止枚举和裸数字/字符串混用)。好处① 传参不会误用别的值paint(1) 会被 mypy 警告、paint(Color.RED) 正确)、② 不同枚举不相等Color.RED == Size.SMALL 为 False 即使 value 都是 1)。代价:和需要「原始值」的接口对接麻烦——存数据库/发 JSON 需要 .valuedb.save(status.value))、还原用值查找(Status(db_value))、不能直接当 int/str 用。理解「纯 Enum 成员!=其 value(Color.RED==1 为 False,比值用.value);类型安全好处传参不误用+不同枚举不相等;代价对接原始值接口要手动.value」,就掌握了类型安全。

四、IntEnum、StrEnum、Flag 等变体

理解枚举的各种变体:

IntEnum:成员"同时也是 int"
  from enum import IntEnum
  class Priority(IntEnum):
      LOW = 1
      HIGH = 10
  Priority.HIGH == 10        # True(IntEnum 和 int 相等!)
  Priority.HIGH > Priority.LOW   # True(可比较大小)
  Priority.LOW + 5           # 6(可参与整数运算)
  → 牺牲一点类型安全,换和 int 的兼容
  → 用于:需要和整数接口/排序/运算对接(如 HTTP 状态码)

StrEnum(Python 3.11+):成员"同时也是 str"
  from enum import StrEnum
  class Env(StrEnum):
      DEV = "dev"
      PROD = "prod"
  Env.DEV == "dev"           # True
  Env.DEV.upper()            # "DEV"(能用字符串方法)
  → 用于:和字符串接口对接(JSON、配置、URL)
  (3.11 前可用 class Env(str, Enum) 达到类似效果)

Flag / IntFlag:位标志(可组合)
  from enum import Flag, auto
  class Perm(Flag):
      READ = auto()          # 1
      WRITE = auto()         # 2
      EXEC = auto()          # 4
  rwx = Perm.READ | Perm.WRITE | Perm.EXEC   # 组合
  Perm.READ in rwx           # True(判断含某标志)
  rwx & Perm.WRITE           # Perm.WRITE(取交集)
  → 用于:权限、开关组合(一个值表示多个标志)

auto():自动赋值
  class X(Enum):
      A = auto()   # 1
      B = auto()   # 2
  → 不关心具体值时用,避免手写 1,2,3...

@unique 装饰器:禁止重复值
  from enum import unique
  @unique
  class C(Enum):
      A = 1
      B = 1   # ✗ ValueError(默认允许别名,@unique 禁止)

所以变体:IntEnum(兼 int)、StrEnum(兼 str,3.11+)、Flag(位标志组合)、auto()自动赋值

枚举的变体IntEnum(成员同时也是 int)——Priority.HIGH == 10 为 True、可比较大小、可参与整数运算(牺牲一点类型安全换 int 兼容、用于 HTTP 状态码等);StrEnum(3.11+,成员同时也是 str)——Env.DEV == "dev" 为 True、能用字符串方法(用于 JSON/配置/URL、3.11 前用 class Env(str, Enum));Flag/IntFlag(位标志、可组合)——Perm.READ | Perm.WRITE 组合、Perm.READ in rwx 判断、用于权限/开关组合;auto()(自动赋值)——不关心具体值时用;@unique 装饰器(禁止重复值)——默认允许别名、@unique 禁止。理解「变体:IntEnum(兼 int 能比较运算,HTTP 状态码)、StrEnum(兼 str,3.11+,JSON/配置)、Flag/IntFlag(位标志|组合,权限)、auto()自动赋值、@unique 禁止重复值」,就掌握了各种变体。

五、别名、方法与进阶

理解枚举的别名和进阶用法:

别名(同值成员):
  class C(Enum):
      A = 1
      ALIAS_A = 1   # 值和 A 相同 → ALIAS_A 是 A 的"别名"
  C.ALIAS_A is C.A   # True(别名指向同一成员)
  list(C)            # 只有 [C.A](别名不出现在迭代中)
  → 允许别名(除非 @unique 禁止)

枚举可以有方法:
  class Color(Enum):
      RED = 1
      GREEN = 2
      def is_warm(self):     # 实例方法
          return self in (Color.RED,)
      @classmethod
      def from_name(cls, n): # 类方法
          return cls[n.upper()]
  Color.RED.is_warm()        # True
  → 枚举是类,可加方法/属性,封装相关逻辑

自定义值(复杂 value):
  class Planet(Enum):
      EARTH = (5.976e24, 6.378e6)   # value 是元组
      def __init__(self, mass, radius):
          self.mass = mass          # 拆成属性
          self.radius = radius
  Planet.EARTH.mass          # 5.976e24

Functional API(动态创建):
  Animal = Enum('Animal', ['DOG', 'CAT', 'BIRD'])
  Animal = Enum('Animal', 'DOG CAT BIRD')   # 字符串也行
  → 动态生成枚举(少用)

序列化注意:
  纯 Enum:存 .value、还原 EnumClass(value)
  IntEnum/StrEnum:可直接序列化(本身是 int/str)
  → JSON 常用 StrEnum 或存 .value

所以别名(同值指向同一成员、不参与迭代)、枚举可加方法、value 可为元组拆属性

别名(同值成员)class C(Enum): A = 1; ALIAS_A = 1——ALIAS_A 是 A 的别名(C.ALIAS_A is C.A 为 True、别名不出现在迭代中、允许别名除非 @unique)。枚举可以有方法def is_warm(self): return self in (Color.RED,)@classmethod from_name(枚举是类、可加方法/属性封装相关逻辑)。自定义值(复杂 value)class Planet(Enum): EARTH = (5.976e24, 6.378e6) + __init__ 拆成属性(Planet.EARTH.mass)。Functional API(动态创建)Enum('Animal', ['DOG', 'CAT'])(动态生成、少用)。序列化注意:纯 Enum 存 .value 还原 EnumClass(value)、IntEnum/StrEnum 可直接序列化。理解「别名(同值指向同一成员、不参与迭代);枚举可加方法(实例/类方法);value 可为元组配__init__拆属性;序列化纯 Enum 存.value、IntEnum/StrEnum 直接序列化」,就掌握了进阶用法。

六、选型与总结

总结枚举的选型:

选型:用哪种枚举

纯 Enum(默认,最安全):
  成员不等于 int/str,类型隔离最强
  用于:内部逻辑、状态机、不需和原始值直接混用
  代价:对接数据库/JSON 要手动 .value

IntEnum:成员兼是 int
  用于:需要和整数比较/排序/运算,或兼容旧整数接口
  例:HTTP 状态码、优先级排序

StrEnum(3.11+)/ class X(str, Enum):成员兼是 str
  用于:和字符串接口对接(JSON、配置、URL、数据库存字符串)
  例:环境名、类型标识

Flag / IntFlag:位标志
  用于:可组合的开关/权限(一个值表示多个标志)

auto():不关心具体值时自动赋值
@unique:禁止重复值(防误写别名)

vs 裸常量:
  枚举全面优于裸常量(类型安全、可读、防无效、可迭代)
  → 表示"一组有限的命名选项"时都该用枚举

核心总结:
  Enum 把命名常量组织成类(name/value、类型安全、成员唯一、可迭代)
  纯 Enum 最安全(成员 != int/str,比值用 .value)
  IntEnum/StrEnum 换 int/str 兼容
  Flag 做位标志、auto() 自动赋值
  比裸常量安全可读

所以纯 Enum 最安全、IntEnum/StrEnum 兼容 int/str、Flag 位标志;都比裸常量好

选型纯 Enum(默认最安全)——成员不等于 int/str、类型隔离最强、用于内部逻辑/状态机(代价对接数据库/JSON 要手动 .value);IntEnum(成员兼是 int)——需要和整数比较/排序/运算或兼容旧整数接口(HTTP 状态码、优先级);StrEnum(3.11+)/class X(str, Enum)(成员兼是 str)——和字符串接口对接(JSON/配置/URL/数据库存字符串);Flag/IntFlag(位标志)——可组合的开关/权限;auto()(自动赋值)、@unique(禁止重复值)。vs 裸常量:枚举全面优于裸常量(表示「一组有限的命名选项」都该用枚举)。理解「纯 Enum 最安全(内部逻辑)、IntEnum(兼 int,状态码/排序)、StrEnum(兼 str,JSON/配置)、Flag(位标志权限);auto()自动/‌@unique 唯一;都比裸常量好」,就掌握了选型与总结。

记忆钩子:「enum.Enum 是 Python 的『枚举』——把一组有限的命名常量定义成类,每个成员有 name(名字)和 value(值):class Color(Enum):RED=1;GREEN=2,访问 Color.RED(成员)、Color.RED.name(‘RED’)、Color.RED.value(1)、Color(1)按值查找、Color[‘RED’]按名查找;★比裸常量的好处:①类型安全(Color.RED 是独立成员,★纯 Enum 里 Color.RED==1 为 False、不会和裸整数/别的枚举混用,比值用.value)②可读(打印 Color.RED 而非无意义的 1)③成员唯一可 is 比较、可迭代 for c in Color(按定义顺序)、可当字典键④防无效值(Color(5)抛 ValueError);★变体按『要不要和 int/str 兼容』选:纯 Enum 最安全但对接数据库/JSON 要手动.value、IntEnum(成员兼是 int、能比较运算 Priority.HIGH==10 为 True,用于 HTTP 状态码/排序)、StrEnum(3.11+成员兼是 str,3.11 前用 class X(str,Enum),用于 JSON/配置)、Flag/IntFlag(位标志、可|组合,用于权限);auto()自动赋值(1,2,3)、@unique 禁止重复值、别名(同值成员指向同一个、不参与迭代);枚举是类可加方法、value 可为元组配__init__拆成属性」

七、常见误区与追问

  • 误区:纯 Enum 的成员等于它的值,Color.RED == 1。Enum 里是 False——枚举成员是独立的对象、不等于它的原始值,Color.RED == 1 为 False,要比较值得用 Color.RED.value == 1;这是故意的类型安全设计(防止枚举和裸整数/字符串混用);如果你需要成员「就是」整数(能和 int 相等、比较、运算),要用 IntEnumPriority.HIGH == 10 为 True);需要「就是」字符串用 StrEnum(3.11+)。
  • 误区:1 in Color 能判断 1 是不是合法的枚举值。 不能——in 判断的是「成员」不是「值」,1 in Color 为 False(1 是值不是成员),Color.RED in Color 才为 True;要判断某个值是否合法,用 Color(1)(合法返回成员、非法抛 ValueError)配合 try/except,或 1 in [c.value for c in Color],或用 Color._value2member_map_(内部映射);注意 Python 3.12+ 对 in 的行为有调整(可以用值判断),但跨版本安全的做法还是用值查找。
  • 误区:枚举定义里两个成员值相同会报错。 默认不报错——值相同的第二个成员会成为第一个的「别名」(ALIAS_A = 1A = 1 的别名、C.ALIAS_A is C.A 为 True、别名不出现在迭代中);如果你想禁止重复值(防止误写),要加 @unique 装饰器,这样重复值才会抛 ValueError;所以「允许别名」是默认行为、「禁止重复」要显式 @unique。
  • 误区:IntEnum 和 Enum 没区别,只是名字不同。 有关键区别——IntEnum 的成员「同时也是 int」:能和整数直接比较相等(Priority.HIGH == 10)、比较大小(HIGH > LOW)、参与算术运算(LOW + 5)、直接序列化成整数;而纯 Enum 的成员和整数完全隔离(== 1 为 False);IntEnum 用「牺牲一点类型安全」换取「和整数接口的兼容性」,适合 HTTP 状态码、需要排序/运算的优先级等;纯 Enum 类型隔离最强、适合不需要和原始值混用的内部逻辑。
  • 追问:枚举相比用模块级常量(如 STATUS_ACTIVE = 1)有什么好处? 主要有:① 类型安全——Status.ACTIVE 有明确类型(Status),函数参数标注 status: Status 后类型检查器能发现误传,而裸常量 1 可以是任何东西、传错也没人拦;② 防无效值——Status(99) 直接抛 ValueError,而 process(99) 用裸常量时会静默接受无意义的值;③ 可读性——打印/日志里是 Status.ACTIVE(自解释)而不是 1(一头雾水);④ 归组——一个类装一组相关常量、有明确归属,不像裸常量散落各处;⑤ 防混用——不同枚举的成员永远不相等(即使值相同),而 STATUS_ACTIVE=2PRIORITY_HIGH=2 会意外相等;⑥ 附加能力——可迭代(遍历所有合法值)、成员判断、当字典键、可加方法;所以表示「一组有限的命名选项」时应该用枚举。
  • 追问:枚举怎么和数据库/JSON 等需要原始值的场景对接? 分情况:① 纯 Enum——存的时候用 .valuedb.save(status.value)json.dumps({"status": status.value})),读回来用值查找还原成员(status = Status(db_value)),因为纯 Enum 成员本身不是 int/str、不能直接序列化;② 用 IntEnumStrEnum(或 class X(str, Enum))——成员「就是」int/str,可以直接序列化(json.dumps 能处理 IntEnum、StrEnum 也能直接当字符串用),读回来时也能直接比较或用值查找;实践中,如果枚举需要频繁和 JSON/数据库/配置文件对接,用 StrEnum(存可读的字符串如 “active”)或 IntEnum(存整数)更省心;如果是纯内部逻辑、追求类型安全,用纯 Enum、序列化时手动 .value
  • 追问:Flag 枚举是干什么的,和普通枚举有什么不同? Flag(和 IntFlag)用于「可组合的位标志」——每个成员对应一个二进制位(通常配合 auto() 得到 1、2、4、8…),可以用位运算 | 组合多个标志成一个值、用 & 取交集、用 in 判断是否包含某标志:比如权限 Perm.READ | Perm.WRITE 表示同时有读写权限、Perm.READ in perms 判断有没有读权限;这和普通枚举(每个成员是互斥的单一选项)不同——普通枚举一个变量只能是一个成员,Flag 一个值能表示多个成员的组合;典型场景是权限系统、功能开关、状态位组合;IntFlag 额外让组合值兼容整数(能和 int 做位运算、序列化成整数,兼容 C 风格的位掩码接口)。

八、加强记忆

enum.Enum 是 Python 的「枚举」——把一组有限的命名常量定义成类,每个成员有 name(名字)和 value(值):class Color(Enum): RED = 1; GREEN = 2,访问 Color.RED(成员)、Color.RED.name(‘RED’)、Color.RED.value(1)、Color(1)(按值查找)、Color['RED'](按名查找)。比裸常量的好处① 类型安全Color.RED 是独立成员,纯 Enum 里 Color.RED == 1 为 False、不会和裸整数/别的枚举混用,比值用 .value)、② 可读(打印 Color.RED 而非无意义的 1)、③ 成员唯一可 is 比较、可迭代 for c in Color(按定义顺序)、可当字典键④ 防无效值Color(5) 抛 ValueError)。变体按「要不要和 int/str 兼容」选:纯 Enum 最安全但对接数据库/JSON 要手动 .valueIntEnum(成员兼是 int、能比较运算、用于 HTTP 状态码/排序);StrEnum(3.11+ 成员兼是 str,3.11 前用 class X(str, Enum)、用于 JSON/配置);Flag/IntFlag(位标志、可 | 组合、用于权限)。auto() 自动赋值、@unique 禁止重复值、别名(同值成员指向同一个、不参与迭代);枚举是类可加方法、value 可为元组配 __init__ 拆成属性。一句话「Enum 把命名常量组织成类(name/value、类型安全、成员唯一、可迭代、防无效值),比裸常量安全可读;纯 Enum 成员!=int/str(比值用.value)、IntEnum/StrEnum 换 int/str 兼容、Flag 做位标志组合、auto()自动赋值」。