enum --- 對列舉的支援

在 3.4 版新加入.

原始碼:Lib/enum.py


列舉:

  • 是一組綁定唯一值的代表名稱(成員)

  • 可以用疊代的方式以定義的順序回傳其正式 (canonical)(即非別名)成員

  • 使用 call 語法來透過值回傳成員

  • 使用 index 語法來透過名稱回傳成員

列舉透過 class 語法或函式呼叫的語法來建立:

>>> from enum import Enum

>>> # class syntax
>>> class Color(Enum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3

>>> # functional syntax
>>> Color = Enum('Color', ['RED', 'GREEN', 'BLUE'])

雖然我們可以用 class 語法來建立列舉,列舉並不是標準的 Python 類別。參考列舉有何差異以取得更多細節。

備註

命名方式

  • Color 類別是一個列舉(或 enum

  • Color.REDColor.GREEN 等屬性是列舉成員(或成員),並且使用上可以看作常數。

  • 列舉成員有名稱Color.RED 的名稱是 REDColor.BLUE 的值是 3 諸如此類)


模組內容

EnumType

Enum 及其子類別的 type

Enum

用來建立列舉常數的基礎類別。

IntEnum

用來建立列舉常數的基礎類別,同時也是 int 的子類別。(備註

StrEnum

用來建立列舉常數的基礎類別,同時也是 str 的子類別。(備註

Flag

用來建立列舉常數的基礎類別,可以使用位元操作來結合成員且其結果不失去 Flag 的成員資格。

IntFlag

用來建立列舉常數的基礎類別,可以使用位元操作來結合成員且其結果不失去 IntFlag 的成員資格。IntFlag 的成員也是 int 的子類別。(備註

ReprEnum

IntEnumStrEnumIntFlag 所使用來保留這些混合類型的 str()

EnumCheck

一個有 CONTINUOUSNAMED_FLAGSUNIQUE 這些值的列舉,和 verify() 一起使用來確保給定的列舉符合多種限制。

FlagBoundary

一個有 STRICTCONFORMEJECTKEEP 這些值的列舉,允許列舉對如何處理非法值做更細微的控制。

auto

列舉成員的實例會被取代成合適的值。StrEnum 預設是小寫版本的成員名稱,其它列舉則預設是 1 且往後遞增。

property()

允許 Enum 成員擁有屬性且不會與成員名稱有衝突。valuename 屬性是用這個方式來實作。

unique()

Enum 類別的裝飾器,用來確保任何值只有綁定到一個名稱上。

verify()

Enum 類別的裝飾器,用來檢查列舉上使用者所選的限制。

member()

obj 變成成員。可以當作裝飾器使用。

nonmember()

不讓 obj 變成成員。可以當作裝飾器使用。

global_enum()

修改列舉上的 str()repr() ,讓成員顯示為屬於模組而不是類別,並將該列舉成員匯出到全域命名空間。

show_flag_values()

回傳旗標 (flag) 裡包含的所有 2 的次方的整數串列。

在 3.6 版新加入: Flag, IntFlag, auto

在 3.11 版新加入: StrEnum, EnumCheck, ReprEnum, FlagBoundary, property, member, nonmember, global_enum, show_flag_values


資料型別

class enum.EnumType

EnumType列舉metaclassEnumType 可以有子類別 -- 細節請參考 建立 EnumType 的子類別

EnumType 負責在最後的列舉上面設定正確的 __repr__()__str__()__format__()__reduce__() 方法,以及建立列舉成員,並正確處理重複,提供列舉類別的疊代等等。

__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)

這個方法可以用兩種不同的方式呼叫:

  • 查詢已存在的成員:

    cls:

    所呼叫的列舉類別。

    value:

    要查詢的值。

  • 使用 cls 列舉來建立新列舉(只有在現有列舉沒有任何成員時)

    cls:

    所呼叫的列舉類別。

    value:

    要建立的新列舉的名稱。

    names:

    新列舉的成員的名稱/值。

    module:

    新列舉要建立在哪個模組名稱下。

    qualname:

    這個列舉在模組裡實際上的位置。

    type:

    新列舉的混合類型。

    start:

    列舉的第一個整數值(由 auto 所使用)

    boundary:

    在位元操作時怎麼處理範圍外的值(只有 Flag 會用到)

__contains__(cls, member)

如果 member 屬於 cls 則回傳 True

>>> some_var = Color.RED
>>> some_var in Color
True
>>> Color.RED.value in Color
True

在 3.12 版的變更: 在 Python 3.12 之前,如果用非列舉成員做屬於檢查 (containment check) 會引發 TypeError

__dir__(cls)

回傳 ['__class__', '__doc__', '__members__', '__module__']cls 的成員名稱:

>>> dir(Color)
['BLUE', 'GREEN', 'RED', '__class__', '__contains__', '__doc__', '__getitem__', '__init_subclass__', '__iter__', '__len__', '__members__', '__module__', '__name__', '__qualname__']
__getitem__(cls, name)

回傳 cls 中符合 name 的列舉成員,或引發 KeyError

>>> Color['BLUE']
<Color.BLUE: 3>
__iter__(cls)

以定義的順序回傳在 cls 中的每個成員:

>>> list(Color)
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]
__len__(cls)

回傳 cls 的成員數量:

>>> len(Color)
3
__members__

回傳每個列舉名稱到其成員的對映,包括別名

__reversed__(cls)

以跟定義相反的順序回傳 cls 的每個成員:

>>> list(reversed(Color))
[<Color.BLUE: 3>, <Color.GREEN: 2>, <Color.RED: 1>]

在 3.11 版新加入: 在 3.11 之前,enum 使用 EnumMeta 類型,目前保留此類型當作別名。

class enum.Enum

Enum 是所有 enum 列舉的基礎類別。

name

用來定義 Enum 成員的名稱:

>>> Color.BLUE.name
'BLUE'
value

Enum 成員給定的值:

>>> Color.RED.value
1

成員的值,可以在 __new__() 設定。

備註

列舉成員的值

成員的值可以是任何值:intstr 等等。如果實際使用什麼值並不重要,你可以使用 auto 實例,它會為你選擇合適的值。更多細節請參考 auto

虽然可以使用可变/不可哈希的值,比如 dict, list 或是可变的 dataclass,但它们在创建期间会产生基于枚举中可变/不可哈希的值数量的指数级性能影响。

_name_

成員名稱。

_value_

成員的值,可以在 __new__() 設定。

_order_

已不再使用,只為了向後相容而保留(類別屬性,在類別建立時移除)

_ignore_

_ignore_ 只有在建立的時候用到,在列舉建立完成後會被移除。

_ignore_ 是一個不會變成成員的名稱串列,在列舉建立完成後其名稱會被移除。範例請參考 TimePeriod

__dir__(self)

回傳 ['__class__', '__doc__', '__module__', 'name', 'value'] 及任何 self.__class__ 上定義的公開方法:

>>> from datetime import date
>>> class Weekday(Enum):
...     MONDAY = 1
...     TUESDAY = 2
...     WEDNESDAY = 3
...     THURSDAY = 4
...     FRIDAY = 5
...     SATURDAY = 6
...     SUNDAY = 7
...     @classmethod
...     def today(cls):
...         print('today is %s' % cls(date.today().isoweekday()).name)
...
>>> dir(Weekday.SATURDAY)
['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'today', 'value']
_generate_next_value_(name, start, count, last_values)
name:

定義的成員名稱(例如 'RED')。

start:

列舉的開始值,預設為 1。

count:

已定義的成員數量,不包含目前這一個。

last_values:

一個之前值的串列。

一個 staticmethod,用來決定 auto 下一個要回傳的值的:

>>> from enum import auto
>>> class PowersOfThree(Enum):
...     @staticmethod
...     def _generate_next_value_(name, start, count, last_values):
...         return 3 ** (count + 1)
...     FIRST = auto()
...     SECOND = auto()
...
>>> PowersOfThree.SECOND.value
9
__init__(self, *args, **kwds)

預設情況下,不執行任何操作。如果在成員賦值中給出多個值,這些值將成為與 __init__ 分別的引數;例如

>>> from enum import Enum
>>> class Weekday(Enum):
...     MONDAY = 1, 'Mon'

Weekday.__init__() 將被稱為 Weekday.__init__(self, 1, 'Mon')

__init_subclass__(cls, **kwds)

一個 classmethod,用來進一步設定後續的子類別,預設不做任何事。

_missing_(cls, value)

一個 classmethod,用來查詢在 cls 裡找不到的值。預設不做任何事,但可以被覆寫以實作客製化的搜尋行為:

>>> from enum import StrEnum
>>> class Build(StrEnum):
...     DEBUG = auto()
...     OPTIMIZED = auto()
...     @classmethod
...     def _missing_(cls, value):
...         value = value.lower()
...         for member in cls:
...             if member.value == value:
...                 return member
...         return None
...
>>> Build.DEBUG.value
'debug'
>>> Build('deBUG')
<Build.DEBUG: 'debug'>
__new__(cls, *args, **kwds)

預設情況下不存在。如果有指定,無論是在列舉類別定義中還是在 mixin 類別中(例如 int),都將傳遞成員賦值中給出的所有值;例如

>>> from enum import Enum
>>> class MyIntEnum(Enum):
...     SEVENTEEN = '1a', 16

int('1a', 16) 调用的结果和成员的值 17

..note:: 當寫自訂的 __new__ 時,不要使用 super().__new__ --

而是呼叫適當的 __new__

__repr__(self)

回傳呼叫 repr() 時使用的字串。預設回傳 Enum 名稱、成員名稱及值,但可以被覆寫:

>>> class OtherStyle(Enum):
...     ALTERNATE = auto()
...     OTHER = auto()
...     SOMETHING_ELSE = auto()
...     def __repr__(self):
...         cls_name = self.__class__.__name__
...         return f'{cls_name}.{self.name}'
...
>>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}"
(OtherStyle.ALTERNATE, 'OtherStyle.ALTERNATE', 'OtherStyle.ALTERNATE')
__str__(self)

回傳呼叫 str() 時使用的字串。預設回傳 Enum 名稱及成員名稱,但可以被覆寫:

>>> class OtherStyle(Enum):
...     ALTERNATE = auto()
...     OTHER = auto()
...     SOMETHING_ELSE = auto()
...     def __str__(self):
...         return f'{self.name}'
...
>>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}"
(<OtherStyle.ALTERNATE: 1>, 'ALTERNATE', 'ALTERNATE')
__format__(self)

回傳呼叫 format()f-string 時使用的字串。預設回傳 __str__() 的回傳值,但可以被覆寫:

>>> class OtherStyle(Enum):
...     ALTERNATE = auto()
...     OTHER = auto()
...     SOMETHING_ELSE = auto()
...     def __format__(self, spec):
...         return f'{self.name}'
...
>>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}"
(<OtherStyle.ALTERNATE: 1>, 'OtherStyle.ALTERNATE', 'ALTERNATE')

備註

Enum 使用 auto 會產生從 1 開始遞增的整數。

在 3.12 版的變更: 新增 数据类支持

class enum.IntEnum

IntEnumEnum 一樣,但其成員同時也是整數而可以被用在任何使用整數的地方。如果 IntEnum 成員經過任何整數運算,其結果會失去列舉狀態。

>>> from enum import IntEnum
>>> class Number(IntEnum):
...     ONE = 1
...     TWO = 2
...     THREE = 3
...
>>> Number.THREE
<Number.THREE: 3>
>>> Number.ONE + Number.TWO
3
>>> Number.THREE + 5
8
>>> Number.THREE == 3
True

備註

IntEnum 使用 auto 會產生從 1 開始遞增的整數。

在 3.11 版的變更: 為了更好地支援現存常數取代 (replacement of existing constants) 的使用情境,__str__() 現在會是 int.__str__()。為了同樣的理由,__format__() 已經是 int.__format__()

class enum.StrEnum

StrEnumEnum 一樣,但其成員同時也是字串而可以被用在幾乎所有使用字串的地方。StrEnum 成員經過任何字串操作的結果會不再是列舉的一部份。

備註

stdlib 裡有些地方會檢查只能是 str 而不是 str 的子類別(也就是 type(unknown) == str 而不是 isinstance(unknown, str)),在這些地方你需要使用 str(StrEnum.member)

備註

StrEnum 使用 auto 會產生小寫的成員名稱當作值。

備註

為了更好地支援現存常數取代 (replacement of existing constants) 的使用情境,__str__() 現在會是 str.__str__()。為了同樣的理由,__format__() 也會是 str.__format__()

在 3.11 版新加入.

class enum.Flag

FlagEnum 相同,但其成員支援位元運算子 & (AND)、| (OR)、^ (XOR) 和 ~ (INVERT);這些運算子的結果是列舉的成員。

__contains__(self, value)

如果 value 在 self 裡則回傳 True

>>> from enum import Flag, auto
>>> class Color(Flag):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...
>>> purple = Color.RED | Color.BLUE
>>> white = Color.RED | Color.GREEN | Color.BLUE
>>> Color.GREEN in purple
False
>>> Color.GREEN in white
True
>>> purple in white
True
>>> white in purple
False
__iter__(self):

回傳所有包含的非別名成員:

>>> list(Color.RED)
[<Color.RED: 1>]
>>> list(purple)
[<Color.RED: 1>, <Color.BLUE: 4>]

在 3.11 版新加入.

__len__(self):

回傳旗標裡的成員數量:

>>> len(Color.GREEN)
1
>>> len(white)
3
__bool__(self):

如果成員在旗標裡則回傳 True,否則回傳 False

>>> bool(Color.GREEN)
True
>>> bool(white)
True
>>> black = Color(0)
>>> bool(black)
False
__or__(self, other)

回傳和 other 做 OR 過後的二進位旗標:

>>> Color.RED | Color.GREEN
<Color.RED|GREEN: 3>
__and__(self, other)

回傳和 other 做 AND 過後的二進位旗標:

>>> purple & white
<Color.RED|BLUE: 5>
>>> purple & Color.GREEN
<Color: 0>
__xor__(self, other)

回傳和 other 做 XOR 過後的二進位旗標:

>>> purple ^ white
<Color.GREEN: 2>
>>> purple ^ Color.GREEN
<Color.RED|GREEN|BLUE: 7>
__invert__(self):

回傳所有在 type(self) 但不在 self 裡的旗標:

>>> ~white
<Color: 0>
>>> ~purple
<Color.GREEN: 2>
>>> ~Color.RED
<Color.GREEN|BLUE: 6>
_numeric_repr_()

用來格式化任何剩下未命名數值的函式。預設是值的 repr,常見選擇是 hex()oct()

備註

Flag 使用 auto 會產生從 1 開始 2 的次方的整數。

在 3.11 版的變更: 值為 0 的旗標的 repr() 已改變。現在是:

>>> Color(0) 
<Color: 0>
class enum.IntFlag

IntFlagFlag 一樣,但其成員同時也是整數而可以被用在任何使用整數的地方。

>>> from enum import IntFlag, auto
>>> class Color(IntFlag):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...
>>> Color.RED & 2
<Color: 0>
>>> Color.RED | 2
<Color.RED|GREEN: 3>

如果 IntFlag 成員經過任何整數運算,其結果不是 IntFlag

>>> Color.RED + 2
3

如果 IntFlag 成員經過 Flag 操作且:

  • 結果是合法的 IntFlag:回傳 IntFlag

  • 結果不是合法的 IntFlag:結果會根據 FlagBoundary 的設定

未命名且值為 0 的旗標的 repr() 已改變。現在是:

>>> Color(0)
<Color: 0>

備註

IntFlag 使用 auto 會產生從 1 開始 2 的次方的整數。

在 3.11 版的變更: 為了更好地支援現存常數取代 (replacement of existing constants) 的使用情境,__str__() 現在會是 int.__str__()。為了同樣的理由,__format__() 已經是 int.__format__()

IntFlag 的反轉 (inversion) 現在會回傳正值,該值是不在給定旗標的所有旗標聯集,而不是一個負值。這符合現有 Flag 的行為。

class enum.ReprEnum

ReprEnum 使用 Enumrepr(),但使用混合資料類型的 str()

繼承 ReprEnum 來保留混合資料類型的 str() / format(),而不是使用 Enum 預設的 str()

在 3.11 版新加入.

class enum.EnumCheck

EnumCheck 包含 verify() 裝飾器使用的選項,以確保多樣的限制,不符合限制會產生 ValueError

UNIQUE

確保每個值只有一個名稱:

>>> from enum import Enum, verify, UNIQUE
>>> @verify(UNIQUE)
... class Color(Enum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3
...     CRIMSON = 1
Traceback (most recent call last):
...
ValueError: aliases found in <enum 'Color'>: CRIMSON -> RED
CONTINUOUS

確保在最小值成員跟最大值成員間沒有缺少值:

>>> from enum import Enum, verify, CONTINUOUS
>>> @verify(CONTINUOUS)
... class Color(Enum):
...     RED = 1
...     GREEN = 2
...     BLUE = 5
Traceback (most recent call last):
...
ValueError: invalid enum 'Color': missing values 3, 4
NAMED_FLAGS

確保任何旗標群組 / 遮罩只包含命名旗標 -- 當值是用指定而不是透過 auto() 產生時是很實用的:

>>> from enum import Flag, verify, NAMED_FLAGS
>>> @verify(NAMED_FLAGS)
... class Color(Flag):
...     RED = 1
...     GREEN = 2
...     BLUE = 4
...     WHITE = 15
...     NEON = 31
Traceback (most recent call last):
...
ValueError: invalid Flag 'Color': aliases WHITE and NEON are missing combined values of 0x18 [use enum.show_flag_values(value) for details]

備註

CONTINUOUS 和 NAMED_FLAGS 是設計用來運作在整數值的成員上。

在 3.11 版新加入.

class enum.FlagBoundary

FlagBoundary 控制在 Flag 及其子類別中如何處理範圍外的值。

STRICT

範圍外的值會引發 ValueError。這是 Flag 的預設行為:

>>> from enum import Flag, STRICT, auto
>>> class StrictFlag(Flag, boundary=STRICT):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...
>>> StrictFlag(2**2 + 2**4)
Traceback (most recent call last):
...
ValueError: <flag 'StrictFlag'> invalid value 20
    given 0b0 10100
  allowed 0b0 00111
CONFORM

範圍外的值會移除非法值,留下合法的 Flag 值:

>>> from enum import Flag, CONFORM, auto
>>> class ConformFlag(Flag, boundary=CONFORM):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...
>>> ConformFlag(2**2 + 2**4)
<ConformFlag.BLUE: 4>
EJECT

範圍外的值會失去它們的 Flag 成員資格且恢復成 int

>>> from enum import Flag, EJECT, auto
>>> class EjectFlag(Flag, boundary=EJECT):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...
>>> EjectFlag(2**2 + 2**4)
20
KEEP

範圍外的值會被保留,Flag 成員資格也會被保留。這是 IntFlag 的預設行為:

>>> from enum import Flag, KEEP, auto
>>> class KeepFlag(Flag, boundary=KEEP):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...
>>> KeepFlag(2**2 + 2**4)
<KeepFlag.BLUE|16: 20>

在 3.11 版新加入.


支援 __dunder__ 名稱

__members__ 是一個唯讀有序的成員名稱成員項目的對映。只有在類別上可用。

如果指定了 __new__(),它必須建立並回傳列舉成員;適當地設定成員的 _value_ 也是一個很好的主意。一旦所有成員都建立之後就不會再被用到。

支援 _sunder_ 名稱

  • _name_ -- 成員名稱

  • _value_ -- 成員的值;可以在 __new__ 設定

  • _missing_() -- 當值沒有被找到時會使用的查詢函式;可以被覆寫

  • _ignore_ -- 一個名稱的串列,可以是 liststr,它不會被轉換成成員,且在最後的類別上會被移除

  • _order_ -- 不再被使用,僅為了向後相容而保留(類別屬性,在類別建立時移除)

  • _generate_next_value_() -- 用來為列舉成員取得合適的值;可以被覆寫

    備註

    對標準的 Enum 類別來說,下一個被選擇的值是最後一個看見的值加一。

    Flag 類別來說,下一個被選擇的值是下一個最大的 2 的次方,不管最後一個看見的值是什麼。

在 3.6 版新加入: _missing__order__generate_next_value_

在 3.7 版新加入: _ignore_


通用項目與裝飾器

class enum.auto

auto 可以用來取代給值。如果使用的話,Enum 系統會呼叫 Enum_generate_next_value_() 來取得合適的值。對 EnumIntEnum 來說,合適的值是最後一個值加一;對 FlagIntFlag 來說,是第一個比最大值還大的 2 的次方的數字;對 StrEnum 來說,是成員名稱的小寫版本。如果混用 auto() 和手動指定值的話要特別注意。

auto 實例只有在最上層的賦值時才會被解析:

  • FIRST = auto() 可以運作(auto() 會被取代成 1

  • SECOND = auto(), -2 可以運作(auto 會被取代成 2, 因此 2, -2 會被用來建立列舉成員 SECOND

  • THREE = [auto(), -3] 無法運作(<auto 實例>, -3 會被用來建立列舉成員 THREE

在 3.11.1 版的變更: 在之前的版本中,auto() 必須是賦值行裡的唯一內容才能運作正確。

可以覆寫 _generate_next_value_ 來客製 auto 使用的值。

備註

在 3.13 預設 _generate_next_value_ 總是回傳最大的成員值加一,如果任何成員是不相容的類型就會失敗。

@enum.property

和內建的 property 相似的裝飾器,但只專門針對列舉。它允許成員屬性和成員本身有相同名稱。

備註

屬性和成員必須定義在分開的類別裡;例如 valuename 屬性定義在 Enum 類別而 Enum 子類別可以定義成員名稱為 valuename

在 3.11 版新加入.

@enum.unique

專門針對列舉的 class 裝飾器。它搜尋列舉的 __members__,蒐集任何它找到的別名;如果有找到任何別名則引發 ValueError 並附上細節:

>>> from enum import Enum, unique
>>> @unique
... class Mistake(Enum):
...     ONE = 1
...     TWO = 2
...     THREE = 3
...     FOUR = 3
...
Traceback (most recent call last):
...
ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
@enum.verify

專門針對列舉的 class 裝飾器。使用 EnumCheck 裡的成員來指定在裝飾的列舉上應該檢查什麼限制。

在 3.11 版新加入.

@enum.member

列舉所使用的裝飾器:其目標會變成成員。

在 3.11 版新加入.

@enum.nonmember

列舉所使用的裝飾器:其目標不會變成成員。

在 3.11 版新加入.

@enum.global_enum

修改列舉的 str()repr() 的裝飾器,讓成員顯示為屬於模組而不是其類別。應該只有當列舉成員被匯出到模組的全域命名空間才使用(範例請參考 re.RegexFlag)。

在 3.11 版新加入.

enum.show_flag_values(value)

回傳在旗標中包含的所有 2 的次方的整數串列。

在 3.11 版新加入.


備註

IntEnumStrEnumIntFlag

這三種列舉類型是設計來直接取代現有以整數及字串為基底的值;因此它們有額外的限制:

  • __str__ 使用值而不是列舉成員的名稱

  • __format__ 因為使用 __str__,也會使用值而不是列舉成員的名稱

如果你不需要或不想要這些限制,你可以透過混合 intstr 類型來建立自己的基礎類別:

>>> from enum import Enum
>>> class MyIntEnum(int, Enum):
...     pass

或者你也可以在你的列舉重新給定合適的 str()

>>> from enum import Enum, IntEnum
>>> class MyIntEnum(IntEnum):
...     __str__ = Enum.__str__