XiWind 西風之劍
HomeTechProContactGitHub
  • About
  • Git
    • Windows Terminal、PowerShell 安裝
    • Git 開始使用
    • Branch 入門
    • 合併多個 Commit , 編輯
    • 額外功能
  • deep learning
    • Dilated Convolution
  • Python
    • GIL 【全域直譯器鎖】
    • PyPy 【JIT 編譯器】
    • Decorator 【修飾器】
      • Class Decorators
  • Python library
    • abc 【抽象 Class】
      • ABC, ABCMeta
      • __abstractmethods__, get_cache_token, update_abstractmethods
    • dataclasses 【數據 Class】
      • make_dataclass(), replace(), is_dataclass(), __post_init__
    • enum 【列舉 Class】
      • Flag, auto(), unique, verify()
      • 範例
    • concurrent.futures 【執行緒、程序】
      • Future, Module Functions
    • queue 【佇列、同步】
      • full(), empty(), qsize(), join(), task_done()
    • functools 【可調用物件】
      • ordering、wrapper、partial
      • Overloading
    • heapq 【堆積佇列】
      • heapify(), merge(), nlargest(), nsmallest()
    • time 【時間】
      • time(), monotonic(), perf_counter()...
      • sleep(), 範例...
    • logging 【日誌】
Powered by GitBook
On this page
  • Flag
  • IntFlag
  • Flag 命名組合
  • Flag boundary 參數
  • auto()
  • 範例 – auto()
  • __generate_next_value__
  • object()
  • @unique, @verify()
  • show_flag_values()
  • __init__
  • 範例 – __init__
  • Functional API

Was this helpful?

  1. Python library
  2. enum 【列舉 Class】

Flag


Flag 與 Enum 的用法大致相同,但它是 Enum 的 Subclass,且 Flag members 支援 bitwise operators & (AND)、| (OR)、^ (XOR) 和 ~ (INVERT); 這些結果值是 enumeration members。

Enum 適合 enumeration members 更加互斥的情況,即,它們不應該組合使用。

Flag 適合 enumeration members 想要組合的情況。 一個用例可以是管理一組使用者權限。

PYTHON
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 的權限。

PYTHON
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 組合。

PYTHON
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 的預設值。

PYTHON
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 定義。

PYTHON
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()


PYTHON
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() ,但需要對分配的值進行更多控制時,這非常有用。

PYTHON
_generate_next_value_(name, start, count, last_values)
參數
說明

name

正在定義的 member's name。

start

Enum 起始值。

count

當前已經定義的 members 數量。

last_values

以前值的 List。

PYTHON
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

PYTHON
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() 實例。 當你運行這個程序時,

PYTHON
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

確切的輸出會有所不同,因為 object() 實例會被輸出為 <object at 0x...>,其中...是物件的 memory 地址。

@unique, @verify()


@unique 確保 enum class 中的所有 enumeration 值都是唯一的 (獨立的); 如果有任何重複,它將引發 ValueError 。

PYTHON
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。

CONTINUOUS,NAMED_FLAGS 僅支援整數的值。

PYTHON
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 值中包含的所有二次冪整數的列表。

PYTHON
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 都有一個名稱和一個縮寫。

PYTHON
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 參數匹配。

請注意,在定義 enum member 後對其進行修改,通常被認為是不好的做法,因為 enums 是 immutable (不可變的)。

範例 – __init__


Enum member 的值存儲在 .value 屬性中,但可以使用 __init__() 向 enum members 加入其他屬性。 這些附加屬性的訪問方式就像 Python 物件的任何其他屬性一樣。

PYTHON
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
PYTHON
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 類型,這些類型基本上是一組值的符號名稱。

PYTHON
Enum(
    value='NewEnumName',
    names=<...>, *,
    module='...',
    qualname='...',
    type=<mixed-in class>,
    start=1)
參數
說明

value

新 enumeration 的名稱。

names

enum members。這可以是 String、mapping、 names iterator 或 (name, value) pairs iterator。 這也可以是空格或逗號分隔的 String(除非另有說明,值將從 1 開始)

module

用作 enum 的 __module__ 屬性。對於 pickling 和 introspection 很有用。

qualname

用作 enum 的 __qualname__ 屬性。對於 introspection 很有用。

type

用作 Mixed-in Class。即,它定義 enumeration 的特定行為。 如果您希望 enum members 表現得像整數、Strings 等,這會很有用。

start

定義 enum members 自動編號的起始編號。

Enum 函數式 API 靈活且用途廣泛,使您能夠創建具有不同行為的複雜 enumeration 類型。

如果未提供 module,並且 Enum 無法確定它是什麼,則新的 Enum members 將不會 unpicklable; 為了使錯誤更接近 source,pickling 將被禁用。

PYTHON
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'>]
PYTHON
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

Previousenum 【列舉 Class】Next範例

Last updated 1 year ago

Was this helpful?

Page cover image