Enum 列舉類[1]
Enum
是一組與互不相同的值分別繫結的符號名,類似於全域性變數。因為列舉通常表示常量,所以建議列舉成員命名時採用大寫。
定義
-
類定義
class Color(Enum): # class syntax RED = 1 GREEN = 2 BLUE = 3
-
方法定義
Color = Enum('Color', ['RED', 'GREEN', 'BLUE']) # functional syntax
-
列舉的成員可以是一個用空格或逗號分隔的字串(值預設
auto
):'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'
-
或是一個名稱的迭代器物件:
['RED', 'GREEN', 'BLUE']
-
或是一個 (名稱, 值) 對的迭代器物件:
[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
-
或是一個對映物件:
{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
-
基本概念
Color = Enum("Color", ["RED", "GREEN"])
assert Color.RED.name == "RED" # 成員的名稱
assert Color.GREEN.value == 2 # 成員的值
- 類
Color
是一個 列舉 (或 enum ) - 屬性
Color.RED
、Color.GREEN
等是列舉成員,並且在功能上是常量。 - 列舉成員有
names
和values
等屬性(Color.RED
的名稱是RED
,Color.GREEN
的值是2
)
🗒️ 備註:有些地方會檢查是否是真正的
str
而不是str
的子類 (例如使用type(unknown) == str
而不是isinstance(unknown, str)
),在這些地方你將需要使用str(StrEnum.member)
。
基本使用方式
Color = Enum("Color", ["RED", "GREEN"])
assert Color(1) == Color.RED # 透過值查詢現有成員
assert Color["GREEN"] == Color.GREEN # 透過名稱查詢現有成員
assert Color.RED in Color # __contains__
assert list(Color) == [i for i in Color] # __iter__,[<Color.RED: 1>, <Color.GREEN: 2>]
assert len(Color) == 2 # __len__,返回 cls 中成員的數量
list(reversed(Color)) # __reversed__,按定義的逆序返回 cls 中的每個成員
特殊使用方式
auto()
enum.auto
例項被替換為列舉成員的適當值。
StrEnum
預設為成員名稱的小寫版本,- 而其他列舉預設為 1 並由此遞增。
_missing_(cls, value)
預設值處理
一個用來查詢不存在於 cls
中的值的類方法。 在預設情況下它將不做任何事,但可以被重寫以實現自定義的搜尋行為:
from enum import StrEnum, auto
class Build(StrEnum):
DEBUG = auto()
OPTIMIZED = auto()
UNKNOWN = auto()
@classmethod
def _missing_(cls, value):
value = value.lower()
for member in cls:
if member.value == value:
return member
return cls.UNKNOWN
print(Build.DEBUG) # debug
print(Build('deBUG')) # debug
print(Build('dev')) # unknown
__init__
vs __new__
如果定義了 __new__()
或 __init__()
,則列舉成員的值將被傳給這些方法。當你想要定製 Enum
成員的實際值時必須使用 __new__()
。 任何其他修改可以用 __new__()
也可以用 __init__()
,應優先使用 __init__()
。
class Planet(Enum):
MERCURY = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
EARTH = (5.976e+24, 6.37814e6)
MARS = (6.421e+23, 3.3972e6)
JUPITER = (1.9e+27, 7.1492e7)
SATURN = (5.688e+26, 6.0268e7)
URANUS = (8.686e+25, 2.5559e7)
NEPTUNE = (1.024e+26, 2.4746e7)
def __init__(self, mass, radius):
self.mass = mass # in kilograms
self.radius = radius # in meters
@property
def surface_gravity(self):
G = 6.67300E-11 # universal gravitational constant (m3 kg-1 s-2)
return G * self.mass / (self.radius * self.radius)
Planet.EARTH.value # (5.976e+24, 6378140.0)
Planet.EARTH.surface_gravity # 9.802652743337129
舉例來說,如果你要向構造器傳入多個條目,但只希望將其中一個作為值:
class Coordinate(bytes, Enum):
"""
Coordinate with binary codes that can be indexed by the int code.
"""
def __new__(cls, value, label, unit):
obj = bytes.__new__(cls, [value])
obj._value_ = value
obj.label = label
obj.unit = unit
return obj
PX = (0, 'P.X', 'km')
PY = (1, 'P.Y', 'km')
VX = (2, 'V.X', 'km/s')
VY = (3, 'V.Y', 'km/s')
print(Coordinate['PY']) # Coordinate.PY
print(Coordinate(3)) # Coordinate.VY
⚠️警告:不要呼叫
super().__new__()
,因為只能找到僅用於查詢的__new__
;請改為直接使用該資料型別。
普通方法和特殊方法
列舉是 Python 的類,可帶有普通方法和特殊方法。假設有如下列舉:
class Mood(Enum):
FUNKY = 1
HAPPY = 3
def describe(self):
# self is the member here
return self.name, self.value
def __str__(self):
return 'my custom str! {0}'.format(self.value)
@classmethod
def favorite_mood(cls):
# cls here is the enumeration
return cls.HAPPY
旗標 Flag
為了符合規範,旗標的值必須為二的乘方,且名稱不可重複。 因此,除了別名的定義 Enum
之外,沒有值 (即 0
) 或是幾個二的乘方值之和 (如 3
) 的旗標也會被視為別名。
class Perm(Flag):
R = 4
W = 2
X = 1
A = R|W|X
assert (Perm.R | Perm.W).name == "R|W" # effectively Perm(0)
assert (Perm.R & Perm.W).name is None # effectively Perm(0)
assert bool(Perm.R & Perm(6)) is True
Python 版本:3.11 ↩︎