<jupyter_start><jupyter_text>Python 中的枚举类型枚举类型可以看作是一种标签或是一系列常量的集合，通常用于表示某些特定的有限集合，例如星期、月份、状态等。Python 的原生类型（Built-in types）里并没有专门的枚举类型，但是我们可以通过很多方法来实现它，例如字典、类等：<jupyter_code>WEEKDAY = {
    'MON': 1,
    'TUS': 2,
    'WEN': 3,
    'THU': 4,
    'FRI': 5
}
class Color:
    RED   = 0
    GREEN = 1
    BLUE  = 2<jupyter_output><empty_output><jupyter_text>上面两种方法可以看做是简单的枚举类型的实现，如果只在局部范围内用到了这样的枚举变量是没有问题的，但问题在于它们都是可变的（mutable），也就是说可以在其它地方被修改从而影响其正常使用：<jupyter_code>WEEKDAY['MON'] = WEEKDAY['FRI']
print(WEEKDAY)<jupyter_output>{'FRI': 5, 'TUS': 2, 'MON': 5, 'WEN': 3, 'THU': 4}<jupyter_text>通过类定义的枚举甚至可以实例化，变得不伦不类：<jupyter_code>c = Color()
print(c.RED)
Color.RED = 2
print(c.RED)<jupyter_output>0
2<jupyter_text>当然也可以使用不可变类型（immutable），例如元组，但是这样就失去了枚举类型的本意，将标签退化为无意义的变量：<jupyter_code>COLOR = ('R', 'G', 'B')
print(COLOR[0], COLOR[1], COLOR[2])<jupyter_output>R G B<jupyter_text>为了提供更好的解决方案，Python 通过 [PEP 435](https://www.python.org/dev/peps/pep-0435) 在 3.4 版本中添加了 [enum](https://github.com/rainyear/cpython/blob/master/Lib/enum.py) 标准库，3.4 之前的版本也可以通过 `pip install enum` 下载兼容支持的库。`enum` 提供了 `Enum`/`IntEnum`/`unique` 三个工具，用法也非常简单，可以通过继承 `Enum`/`IntEnum` 定义枚举类型，其中 `IntEnum` 限定枚举成员必须为（或可以转化为）整数类型，而 `unique` 方法可以作为修饰器限定枚举成员的值不可重复：<jupyter_code>from enum import Enum, IntEnum, unique

try:
    @unique
    class WEEKDAY(Enum):
        MON = 1
        TUS = 2
        WEN = 3
        THU = 4
        FRI = 1
except ValueError as e:
    print(e)
try:
    class Color(IntEnum):
        RED   = 0
        GREEN = 1
        BLUE  = 'b'
except ValueError as e:
    print(e)<jupyter_output>invalid literal for int() with base 10: 'b'<jupyter_text>更有趣的是 `Enum` 的成员均为单例（Singleton），并且不可实例化，不可更改：<jupyter_code>class Color(Enum):
    R = 0
    G = 1
    B = 2
try:
    Color.R = 2
except AttributeError as e:
    print(e)<jupyter_output>Cannot reassign members.<jupyter_text>虽然不可实例化，但可以将枚举成员赋值给变量：<jupyter_code>red = Color(0)
green = Color(1)
blue = Color(2)
print(red, green, blue)<jupyter_output>Color.R Color.G Color.B<jupyter_text>也可以进行比较判断：<jupyter_code>print(red is Color.R)
print(red == Color.R)
print(red is blue)
print(green != Color.B)
print(red == 0) # 不等于任何非本枚举类的值<jupyter_output>True
True
False
True
False<jupyter_text>最后一点，由于枚举成员本身也是枚举类型，因此也可以通过枚举成员找到其它成员：<jupyter_code>print(red.B)
print(red.B.G.R)<jupyter_output>Color.B
Color.R<jupyter_text>但是要谨慎使用这一特性，因为可能与成员原有的命名空间中的名称相冲突：<jupyter_code>print(red.name, ':', red.value)

class Attr(Enum):
    name  = 'NAME'
    value = 'VALUE'
print(Attr.name.value, Attr.value.name)<jupyter_output>R : 0
NAME value
{'fraction_non_alphanumeric': 0.14627450980392157, 'fraction_numerical': 0.018823529411764704, 'mean_word_length': 5.283251231527093, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 32, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '250804', 'license': 'MIT', 'n_tokens_mistral': 1471, 'n_tokens_neox': 1490, 'n_words': 173, 'path': 'Tips/2016-04-30-Enum.ipynb', 'repo_name': 'guoweikuang/pytips', 'size': '2550'}