Flag
Flag
與 Enum
的用法大致相同,但它是 Enum
的 Subclass,且 Flag members 支援 bitwise operators &
(AND)、|
(OR)、^
(XOR) 和 ~
(INVERT); 這些結果值是 enumeration members。
Enum
適合 enumeration members 更加互斥的情況,即,它們不應該組合使用。
Flag
適合 enumeration members 想要組合的情況。 一個用例可以是管理一組使用者權限。
Copy import enum
class Permission(enum.Flag):
READ = enum.auto()
WRITE = enum.auto()
EXECUTE = enum.auto()
W=enum.auto()
# Individual permissions
print(Permission.READ.value) # Output: 1
print(Permission.WRITE.value) # Output: 2
print(Permission.EXECUTE.value) # Output: 4
# Combined permissions
read_write = Permission.READ | Permission.WRITE
print(read_write) # Output: Permission.READ|WRITE
# Checking if a certain permission is in the combination
print(Permission.READ in read_write) # Output: True
print(type(read_write)) # <flag 'Permission'>
IntFlag
IntFlag
與 Flag
的用法大致相同,但它是 Flag
的 Subclass ,且 enumeration 值是 str
的實例。
IntFlag
更進一步,使 enumeration members 的行為更像整數。IntFlag
members ,可以參與所有 int
的 operations。如果對 IntFlag
members 執行任何整數運算,則結果值將失去 enumeration 狀態。
IntFlag
和 Enum
之間的另一個重要區別是,如果沒有設置 Flag(值會為0),則 bool()
評估為 False
。
自定義 IntFlag
members 時要小心,以避免意外地將組合定義為單個權限。或是直接使用 auto
定義 members。
例如:為 member 分配 3
的權限,將意味著它同時包含 1
和 2
的權限。
Copy import enum
class Permission(enum.IntFlag):
NONE = 0
READ = 1
WRITE = 2
EXECUTE = 4
ALL = 7
# Individual permissions
print(Permission.READ) # Output: 1
# Combined permissions
read_write = Permission.READ | Permission.WRITE
print(read_write) # Output: 3
print(type(read_write)) # Output: <flag 'Permission'>
# Checking if a certain permission is in the combination
print(Permission.READ in read_write) # Output: True
# Compare with integers
print(Permission.ALL == 7) # Output: True
print(Permission.ALL & Permission.NONE) # Output: 0
print(bool(Permission.ALL & Permission.NONE)) # Output: False
Flag 命名組合
命名組合被視為別名。別名在 iteration 期間不會顯示,但可以使用值查找。 IntFlag
members 也是 int
的 Subclass,所以可以與 int 組合。
Copy from enum import IntFlag
class Perm(IntFlag):
R = 4
W = 2
X = 1
print(Perm.R | Perm.W) # Output: 6
print(Perm.R + Perm.W) # Output: 6
RW = Perm.R | Perm.W
print(Perm.R in RW) # Output: True
Flag boundary 參數
控制 Flag
及其 Subclasses 中如何處理超出範圍的值。
KEEP
:超出範圍的值將被保留,並且 Flag
membership 將被保留。這是 IntFlag
的預設值。 EJECT
: 超出範圍的值將失去其 Flag
membership ,並恢復為 int
。 CONFORM
: 超出範圍的值已將刪除無效值,留下有效的 Flag
值: STRICT
: 超出範圍的值會導致引發 ValueError。這是 Flag
的預設值。
Copy import enum
class KeepFlag(enum.Flag, boundary=enum.KEEP):
RED = enum.auto()
GREEN = enum.auto()
BLUE = enum.auto()
print(KeepFlag(2**2)) # Output: KeepFlag.BLUE
print(KeepFlag(2**2 + 2**4)) # Output: KeepFlag.BLUE|16
print(KeepFlag.RED.value) # Output: 1
print(KeepFlag.GREEN.value) # Output: 2
print(KeepFlag.BLUE.value) # Output: 4
# =========================================================
class KeepFlag(enum.Flag, boundary=enum.EJECT):
RED = enum.auto()
GREEN = enum.auto()
BLUE = enum.auto()
print(KeepFlag(2**2 + 2**4)) # Output: 20
# =========================================================
class KeepFlag(enum.Flag, boundary=enum.CONFORM):
RED = enum.auto()
GREEN = enum.auto()
BLUE = enum.auto()
print(KeepFlag(2**2 + 2**4)) # Output: KeepFlag.BLUE
# =========================================================
class KeepFlag(enum.Flag, boundary=enum.STRICT):
RED = enum.auto()
GREEN = enum.auto()
BLUE = enum.auto()
print(KeepFlag(2**2 + 2**4))
'''
Output:
ValueError: <flag 'KeepFlag'> invalid value 20
given 0b0 10100
allowed 0b0 00111
'''
auto()
auto
可以用來代替 Enum 的值,其值是 auto
的實例。 是一個為 Enum members 生成值的 Class。目的是簡化 enumerations 的創建,其中 members 的確切值並不重要,從而使開發人員能夠專注於程式碼中更有意義的部分。
使用 auto
時,將調用 Enum 的 _generate_next_value_()
來獲取適當的值。
對於 Enum
和 IntEnum
,Enum 的值將是最後一個值加 1。
對於 Flag
和 IntFlag
,Enum 的值將是第一個大於最高值的 2 的冪 (次方)。
對於 StrEnum
,Enum 的值將是 member’s name 的小寫版本。
如果將 auto()
與手動指定的 Enum 值混合使用時,必須小心。
Python 3.11.1 更新。
3.11.1 之前 : auto()
必須是賦值右側的唯一項。
3.11.1 開始 :您可以以更靈活的方式使用 auto()
,可以同一行上的其他表達式或值組合起來。這允許更複雜的 enum 定義。
Copy from enum import Enum, auto
# After Python 3.11.1
class Color(Enum):
RED = auto()
GREEN = auto(), -2
YELLOW = (auto(), -3)
BLUE = [auto(), -3] # ❌❌
print(Color.RED.value) # Output: 1
print(Color.GREEN.value) # Output: (2, -2)
print(Color.YELLOW.value) # Output: (3, -3)
print(Color.BLUE.value) # Output: [auto(_auto_null), -3]
# =========================================================
# Before Python 3.11.1
class Color(Enum):
RED = auto()
GREEN = auto(), -2 # ❌❌
YELLOW = (auto(), -3) # ❌❌
BLUE = [auto(), -3] # ❌❌
print(Color.RED.value) # Output: 1
print(Color.GREEN.value) # Output: (<enum.auto object at 0x0000015851FCBFD0>, -2)
print(Color.YELLOW.value) # Output: (<enum.auto object at 0x0000015851FCBF40>, -3)
print(Color.BLUE.value) # Output: [<enum.auto object at 0x0000015851FCBF10>, -3]
範例 – auto()
Copy from enum import Enum, auto
# Enumeration has eight members
# Representing the eight planets of the Solar System.
class Planet(Enum):
MERCURY = auto()
VENUS = auto()
EARTH = auto()
MARS = auto()
JUPITER = auto()
SATURN = auto()
URANUS = auto()
NEPTUNE = auto()
def describe(self):
if self == Planet.EARTH:
return "Home, sweet home!"
else:
return "This is planet " + self.name
print(Planet.EARTH.describe()) # Output: Home, sweet home!
print(Planet.MARS.describe()) # Output: This is planet MARS
print(Planet.EARTH.value < Planet.MARS.value) # Output: True
__generate_next_value__
您可以重寫 enumeration classes 中的 _generate_next_value_
方法來更改 auto()
為 members 賦值的方式。 當您想要使用 auto()
,但需要對分配的值進行更多控制時,這非常有用。
Copy _generate_next_value_(name, start, count, last_values)
Copy from enum import Enum, auto
class PowersOfThree(Enum):
@staticmethod # 需求 python 3.10 以上
def _generate_next_value_(name, start, count, last_values):
return 3 * (count + 1)
FIRST = auto()
SECOND = auto()
THIRD = auto()
print(PowersOfThree.FIRST.value) # Output: 3
print(PowersOfThree.SECOND.value) # Output: 6
print(PowersOfThree.THIRD.value) # Output: 9
Copy import enum
class AutoName(enum.Enum):
def _generate_next_value_(name, start, count, last_values):
return name
class Ordinal(AutoName):
NORTH = enum.auto()
SOUTH = enum.auto()
EAST = enum.auto()
WEST = enum.auto()
print(list(Ordinal))
# Output:
# [<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]
object()
object()
是 Python 中的一個 built-in 函數,它返回一個新的無特徵物件。 object
是所有 Class 的基礎,它包含所有 Class 預設的 built-in 屬性和方法。
當您希望每個 enum member 都具有真正唯一且明確的值時,這可能很有用。例如:避免某些類型的錯誤,尤其是在具有許多 enum 類型的大型程序中。
然而,使用 object()
實例作為 enum 值也有一些缺點。 例如:這些值不是人類可讀的,並且無法序列化為 JSON 或其他格式。 它還可能使 debugging 變得更加困難,因為這些值不提供有關它們所代表的內容的任何訊息。 因此,請謹慎使用此功能,並考慮您的具體情況是否利大於弊。
在此範例中,Unique
enum 具有三個 members,每個 member 的值都是唯一的 object()
實例。 當你運行這個程序時,
Copy from enum import Enum
class Unique(Enum):
FIRST = object()
SECOND = object()
THIRD = object()
print(Unique.FIRST.value) # Output: <object object at 0x000002CE0C8D4260>
print(Unique.SECOND.value) # Output: <object object at 0x000002CE0C8D4260>
print(Unique.THIRD.value) # Output: <object object at 0x000002CE0C8D4270>
print(Unique.FIRST.value == Unique.SECOND.value) # Output: False
@unique, @verify()
@unique
確保 enum class 中的所有 enumeration 值都是唯一的 (獨立的); 如果有任何重複,它將引發 ValueError 。
Copy import enum
@enum.unique
class Color(enum.Enum):
RED = 1
GREEN = 2
BLUE = 2
def describe(self):
# this is a member function
return f"This is a color with value {self.value}"
@classmethod
def favorite_color(cls):
return cls.GREEN
# Usage:
print(Color.RED) # Output: Color.RED
print(Color.RED.value) # Output: 1
print(Color.RED.describe()) # Output: This is a color with value 1
print(Color.favorite_color()) # Output: Color.GREEN
'''
Output:
ValueError: duplicate values found in <enum 'Color'>: BLUE -> GREEN
'''
verify()
decorator 用於確保各種限制條件; 失敗的限制條件會導致 ValueError。
UNIQUE
: 確保每個值只有唯一的 enum member。 CONTINUOUS
: 確保最低值的 member 和最高值的 member 之間不存在缺失值。 NAMED_FLAGS
: 確保任何 flag 包含已經命名的 flags。當 flag 的值由 auto()
生成時,忽略檢查該 flag。
Copy import enum
@enum.verify(enum.UNIQUE)
class Color(enum.Enum):
RED = 1
GREEN = 2
BLUE = 3
CRIMSON = 1
# Output:
# ValueError: aliases found in <enum 'Color'>: CRIMSON -> RED
@enum.verify(enum.CONTINUOUS)
class Color(enum.Enum):
RED = 1
GREEN = 2
BLUE = 5
# Output:
# ValueError: invalid enum 'Color': missing values 3, 4
@enum.verify(enum.NAMED_FLAGS)
class Color(enum.Flag):
RED = 1
GREEN = 2
BLUE = 4
WHITE = 15
NEON = 31
# ValueError: invalid Flag 'Color': aliases WHITE and NEON are missing combined values of 0x18
# [use enum.show_flag_values(value) for details]
print(enum.show_flag_values(15)) # Output: [1, 2, 4, 8]
print(enum.show_flag_values(31)) # Output: [1, 2, 4, 8, 16]
show_flag_values()
show_flag_values(value)
返回 flag 值中包含的所有二次冪整數的列表。
Copy import enum
class Color(enum.Flag):
RED = 1
GREEN = 2
BLUE = 4
WHITE = 15
NEON = 31
print(enum.show_flag_values(15)) # Output: [1, 2, 4, 8]
print(enum.show_flag_values(31)) # Output: [1, 2, 4, 8, 16]
__init__
__init__()
用於在創建 Class 的實例後對其進行初始化。 在 Enum
的 context 中,__init__()
方法可用於為 enum 的每個 member 執行附加設置。
範例 1 :為 enum members 分配附加屬性,每個 member 都有一個名稱和一個縮寫。
Copy from enum import Enum
class State(Enum):
Alabama = ('AL', 'Montgomery')
Alaska = ('AK', 'Juneau')
def __init__(self, abbreviation, capital):
self.abbreviation = abbreviation
self.capital = capital
print(State.Alabama) # Output: State.Alabama
print(State.Alabama.abbreviation) # Output: 'AL'
print(State.Alabama.capital) # Output: 'Montgomery'
重寫 __init__()
來為 enum 的每個 member 提供額外的設置。__init__()
不返回任何內容; 相反,它直接修改實例。 如果您嘗試從 __init__()
返回除 None
之外的任何內容,您將得到一個 TypeError
。
__init__()
的參數必須與定義 enum members 時提供的值匹配。 在 State
Class 中,每個 enum member 都使用兩個 Tuple Strings 定義,這兩個 Strings 與 __init__()
的abbreviation
和 capital
參數匹配。
範例 – __init__
Enum member 的值存儲在 .value
屬性中,但可以使用 __init__()
向 enum members 加入其他屬性。 這些附加屬性的訪問方式就像 Python 物件的任何其他屬性一樣。
Copy from enum import Enum
class Month(Enum):
January = 1
February = 2
March = 3
# ...
def __init__(self, index):
self.index = index
self.days = self.compute_days()
def compute_days(self):
if self.index in (1, 3):
return 31
elif self.index == 2:
return 28
else:
return 30
print(Month.January.value) # Output: 1
print(Month.January.index) # Output: 1
print(Month.January.days) # Output: 31
print(Month.February.value) # Output: 2
print(Month.February.index) # Output: 2
print(Month.February.days) # Output: 28
Copy from enum import Enum
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):
# universal gravitational constant (m3 kg-1 s-2)
G = 6.67300E-11
return G * self.mass / (self.radius * self.radius)
print(Planet.EARTH.value) # Output: (5.976e+24, 6378140.0)
print(Planet.EARTH.mass) # Output: 5.976e+24
print(Planet.EARTH.radius) # Output: 6378140.0
print(Planet.EARTH.surface_gravity) # Output: 9.802652743337129
Functional API
Enum
函數 API 允許您創建 enumeration 類型,這些類型基本上是一組值的符號名稱。
Copy Enum(
value='NewEnumName',
names=<...>, *,
module='...',
qualname='...',
type=<mixed-in class>,
start=1)
enum members。這可以是 String、mapping、 names iterator 或 (name, value) pairs iterator。 這也可以是空格或逗號分隔的 String(除非另有說明,值將從 1 開始)
用作 enum 的 __module__
屬性。對於 pickling 和 introspection 很有用。
用作 enum 的 __qualname__
屬性。對於 introspection 很有用。
用作 Mixed-in Class。即,它定義 enumeration 的特定行為。 如果您希望 enum members 表現得像整數、Strings 等,這會很有用。
定義 enum members 自動編號的起始編號。
如果未提供 module
,並且 Enum 無法確定它是什麼,則新的 Enum members 將不會 unpicklable; 為了使錯誤更接近 source,pickling 將被禁用。
Copy from enum import Enum, StrEnum
Color = Enum("Color", 'RED GREEN BLUE')
Color = Enum("Color", 'RED,GREEN,BLUE')
Color = Enum("Color", 'RED, GREEN, BLUE')
Color = Enum("Color", ['RED', 'GREEN', 'BLUE'])
Color = Enum("Color", [('RED', 1), ('GREEN', 2), ('BLUE', 3)])
Color = Enum("Color", {"RED": 1, 'GREEN': 2, 'BLUE': 3})
print(list(Color)) # Output: [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]
Fruit = Enum("Fruit", ["APPLE", "BANANA", "CHERRY"], start=10)
print(list(Fruit)) # Output: [<Fruit.APPLE: 10>, <Fruit.BANANA: 11>, <Fruit.CHERRY: 12>]
Color = Enum("Color", {"RED": "#FF0000",
"GREEN": "#008000",
"BLUE": "#0000FF"})
print(list(Color)) # Output: [<Color.RED: '#FF0000'>,
#<Color.GREEN: '#008000'>,
#<Color.BLUE: '#0000FF'>]
# Using mixed-in type
class CustomEnum(StrEnum):
pass
Direction = Enum("Direction", "NORTH EAST SOUTH WEST", type=CustomEnum)
print(list(CustomEnum)) # Output: []
print(list(Direction)) # Output: [<Direction.NORTH: '1'>, <Direction.EAST: '2'>,
# <Direction.SOUTH: '3'>, <Direction.WEST: '4'>]
Copy from enum import Enum
# Creating an Enum using functional API
Fruit = Enum(
value="Fruit",
names=["APPLE", "BANANA", "CHERRY"],
module='main',
qualname='main.Fruit',)
print(Fruit.__module__) # Outputs: main
print(Fruit.__qualname__) # Outputs: main.Fruit