PEP 354 – Python 中的枚举
- 作者:
- Ben Finney <ben+python at benfinney.id.au>
- 状态:
- 已取代
- 类型:
- 标准跟踪
- 创建日期:
- 2005年12月20日
- Python 版本:
- 2.6
- 发布历史:
- 2005年12月20日
- 取代者:
- 435
拒绝通知
此 PEP 已被拒绝。它没有很好地融入任何现有模块(如 collections),并且 Python 标准库避免在其自身模块中包含大量单独的数据结构。此外,此 PEP 未引起广泛兴趣。对于那些需要枚举的人来说,有 cookbook 菜谱和 PyPI 包可以满足这些需求。
摘要
此 PEP 规定了一种用于 Python 的枚举数据类型。
枚举是一组独占的符号名称,绑定到任意唯一值。枚举中的值可以被迭代和比较,但这些值与枚举外部的值没有内在的关联。
动机
枚举的属性对于定义一个不变的、相关的常量值集合非常有用,这些值具有定义的顺序但没有内在的语义含义。经典的例子是星期几(周日到周六)和学校评分(“A”到“D”,以及“F”)。其他例子包括错误状态值和定义过程中的状态。
可以通过简单地定义某种其他基本类型(如 int
或 str
)的值序列来表示离散的任意值。但是,枚举确保这些值与其他任何值不同,并且像“星期三乘以二”这样没有意义的操作不会为这些值定义。
规范
枚举类型是通过类型构造函数的参数序列创建的
>>> Weekdays = enum('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat')
>>> Grades = enum('A', 'B', 'C', 'D', 'F')
没有值的枚举是无意义的。如果构造函数在没有值参数的情况下被调用,则会引发异常 EnumEmptyError
。
值绑定到新枚举对象的属性
>>> today = Weekdays.mon
值可以被比较
>>> if today == Weekdays.fri:
... print "Get ready for the weekend"
枚举中的值只能与来自同一枚举的值进行有意义的比较。当枚举中的值与来自同一枚举以外的任何值或不同类型的值进行比较时,比较操作函数将返回 NotImplemented
[1]。
>>> gym_night = Weekdays.wed
>>> gym_night.__cmp__(Weekdays.mon)
1
>>> gym_night.__cmp__(Weekdays.wed)
0
>>> gym_night.__cmp__(Weekdays.fri)
-1
>>> gym_night.__cmp__(23)
NotImplemented
>>> gym_night.__cmp__("wed")
NotImplemented
>>> gym_night.__cmp__(Grades.B)
NotImplemented
这允许操作成功,并计算为布尔值
>>> gym_night = Weekdays.wed
>>> gym_night < Weekdays.mon
False
>>> gym_night < Weekdays.wed
False
>>> gym_night < Weekdays.fri
True
>>> gym_night < 23
False
>>> gym_night > 23
True
>>> gym_night > "wed"
True
>>> gym_night > Grades.B
True
将枚举中的值强制转换为 str
会得到在构造枚举时为该值指定的字符串
>>> gym_night = Weekdays.wed
>>> str(gym_night)
'wed'
枚举中每个值的序列索引通过该值的 index
属性导出为整数
>>> gym_night = Weekdays.wed
>>> gym_night.index
3
枚举可以被迭代,返回其在创建枚举时指定的顺序的值
>>> print [str(day) for day in Weekdays]
['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
枚举中的值是可哈希的,可以用作字典键
>>> plans = {}
>>> plans[Weekdays.sat] = "Feed the horse"
枚举的正常用法是为数据类型提供一组可能的值,然后可以使用这些值来映射到关于这些值的信息
>>> for report_grade in Grades:
... report_students[report_grade] = \
... [s for s in students if students.grade == report_grade]
原理 – 考虑过的其他设计
合而为一的类
某些实现将枚举及其值都作为单个对象或类的属性。
此 PEP 规定了一种设计,其中枚举是一个容器,而值是简单的可比对象。人们认为,试图将枚举的所有属性放在一个类中会使设计复杂化,而没有明显的益处。
用于创建枚举类的元类
此 PEP 中规定的枚举是 enum
类型的实例。一些替代设计为每个枚举实现一个单独的类,并使用一个元类来定义所有枚举的通用属性。
为每个枚举创建一个类(而不是实例)的一个动机是允许枚举的子类,从而扩展和修改现有枚举。但是,类意味着将创建该类的实例;很难想象一个“一周中的几天”类的单独实例意味着什么,其中每个实例都包含所有天。这通常会导致每个类遵循单例模式,从而进一步使设计复杂化。
相比之下,此 PEP 规定的枚举不期望被扩展或修改。当然,如果需要,可以从现有枚举的字符串值创建新枚举,甚至可以子类化 enum
类型。
隐藏枚举值的属性
以前的设计使枚举值尽可能隐藏其实现的细节,甚至不导出字符串键和序列索引。
此 PEP 中的设计承认程序通常会发现了解枚举值的枚举类型、序列索引和为该值指定的字符串键很方便。这些作为属性由枚举值导出。
实施
此设计部分基于 Python Cookbook 中的一个菜谱 [2]。
PyPI 包 enum
[3] 提供了此 PEP 中所述数据类型的 Python 实现。
参考文献和脚注
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0354.rst