> For the complete documentation index, see [llms.txt](https://docs.xiwind-corp.com/tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xiwind-corp.com/tech/python-library/enum-lie-ju-class/flag-auto-unique-verify.md).

# Flag, auto(), unique, verify()

## Flag

***

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

{% hint style="success" %}
**`Enum` 適合 enumeration members 更加互斥的情況，即，它們不應該組合使用。**

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

{% code title="PYTHON" %}

```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'>
```

{% endcode %}

### IntFlag

***

`IntFlag` 與 `Flag` 的用法大致相同，但它是 `Flag` 的 Subclass ，且 enumeration 值是 `str` 的實例。

`IntFlag` 更進一步，使 enumeration members 的行為更像整數。`IntFlag` members ，可以參與所有 `int` 的 operations。如果對 `IntFlag` members 執行任何整數運算，則結果值將失去 enumeration 狀態。

`IntFlag` 和 `Enum` 之間的另一個重要區別是，如果沒有設置 Flag(值會為0)，則 `bool()` 評估為 `False`。

{% hint style="success" %}
**自定義 `IntFlag` members 時要小心，以避免意外地將組合定義為單個權限。或是直接使用 `auto` 定義 members。**&#x20;

例如：為 member 分配 `3` 的權限，將意味著它同時包含 `1` 和 `2` 的權限。
{% endhint %}

{% code title="PYTHON" %}

```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
```

{% endcode %}

### Flag 命名組合

***

命名組合被視為別名。別名在 iteration 期間不會顯示，但可以使用值查找。 `IntFlag` members 也是 `int` 的 Subclass，所以可以與 int 組合。

{% code title="PYTHON" %}

```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
```

{% endcode %}

### Flag boundary 參數

***

控制 `Flag` 及其 Subclasses 中如何處理超出範圍的值。

`KEEP`：超出範圍的值將被保留，並且 `Flag` membership 將被保留。這是 `IntFlag` 的預設值。 `EJECT`: 超出範圍的值將失去其 `Flag` membership ，並恢復為 `int`。 `CONFORM`: 超出範圍的值已將刪除無效值，留下有效的 `Flag` 值： `STRICT`: 超出範圍的值會導致引發 ValueError。這是 `Flag` 的預設值。

{% code title="PYTHON" %}

```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
'''
```

{% endcode %}

## 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 值混合使用時，必須小心。

{% hint style="success" %}
**Python 3.11.1 更新。**&#x20;

**3.11.1 之前**: `auto()` 必須是賦值右側的唯一項。&#x20;

**3.11.1 開始**：您可以以更靈活的方式使用 `auto()` ，可以同一行上的其他表達式或值組合起來。這允許更複雜的 enum 定義。
{% endhint %}

{% code title="PYTHON" %}

```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]
```

{% endcode %}

### 範例 – auto()

***

{% code title="PYTHON" %}

```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
```

{% endcode %}

### \_\_generate\_next\_value\_\_

***

您可以重寫 enumeration classes 中的 `_generate_next_value_` 方法來更改 `auto()` 為 members 賦值的方式。 當您想要使用 `auto()` ，但需要對分配的值進行更多控制時，這非常有用。

{% code title="PYTHON" %}

```python
_generate_next_value_(name, start, count, last_values)
```

{% endcode %}

<table><thead><tr><th width="188">參數</th><th>說明</th></tr></thead><tbody><tr><td><strong>name</strong></td><td>正在定義的 member's name。</td></tr><tr><td><strong>start</strong></td><td>Enum 起始值。</td></tr><tr><td><strong>count</strong></td><td>當前已經定義的 members 數量。</td></tr><tr><td><strong>last_values</strong></td><td>以前值的 List。</td></tr></tbody></table>

{% code title="PYTHON" %}

```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
```

{% endcode %}

{% code title="PYTHON" %}

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

{% endcode %}

## object()

***

`object()` 是 Python 中的一個 built-in 函數，它返回一個新的無特徵物件。 `object` 是所有 Class 的基礎，它包含所有 Class 預設的 built-in 屬性和方法。

當您希望每個 enum member 都具有真正唯一且明確的值時，這可能很有用。例如：避免某些類型的錯誤，尤其是在具有許多 enum 類型的大型程序中。

然而，使用 `object()` 實例作為 enum 值也有一些缺點。 例如：這些值不是人類可讀的，並且無法序列化為 JSON 或其他格式。 它還可能使 debugging 變得更加困難，因為這些值不提供有關它們所代表的內容的任何訊息。 因此，請謹慎使用此功能，並考慮您的具體情況是否利大於弊。

在此範例中，`Unique` enum 具有三個 members，每個 member 的值都是唯一的 `object()` 實例。 當你運行這個程序時，

{% code title="PYTHON" %}

```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
```

{% endcode %}

{% hint style="info" %}
**確切的輸出會有所不同，因為 `object()` 實例會被輸出為 `<object at 0x...>`，其中`...`是物件的 memory 地址。**
{% endhint %}

## @unique, @verify()

***

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

{% code title="PYTHON" %}

```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
'''
```

{% endcode %}

`verify()` decorator 用於確保各種限制條件； 失敗的限制條件會導致 ValueError。

`UNIQUE`: 確保每個值只有唯一的 enum member。 `CONTINUOUS`: 確保最低值的 member 和最高值的 member 之間不存在缺失值。 `NAMED_FLAGS`: 確保任何 flag 包含已經命名的 flags。當 flag 的值由 `auto()` 生成時，忽略檢查該 flag。

{% hint style="info" %}
**`CONTINUOUS`，`NAMED_FLAGS` 僅支援整數的值。**
{% endhint %}

{% code title="PYTHON" %}

```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]

```

{% endcode %}

## show\_flag\_values()

***

`show_flag_values(value)` 返回 flag 值中包含的所有二次冪整數的列表。

{% code title="PYTHON" %}

```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]
```

{% endcode %}

## \_\_init\_\_

***

`__init__()` 用於在創建 Class 的實例後對其進行初始化。 在 `Enum` 的 context 中，`__init__()` 方法可用於為 enum 的每個 member 執行附加設置。

**範例 1**：為 enum members 分配附加屬性，每個 member 都有一個名稱和一個縮寫。

{% code title="PYTHON" %}

```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'
```

{% endcode %}

重寫 `__init__()` 來為 enum 的每個 member 提供額外的設置。`__init__()` 不返回任何內容； 相反，它直接修改實例。 如果您嘗試從 `__init__()` 返回除 `None` 之外的任何內容，您將得到一個 `TypeError`。

`__init__()` 的參數必須與定義 enum members 時提供的值匹配。 在 `State` Class 中，每個 enum member 都使用兩個 Tuple Strings 定義，這兩個 Strings 與 `__init__()` 的`abbreviation` 和 `capital` 參數匹配。

{% hint style="info" %}
請注意，在定義 enum member 後對其進行修改，通常被認為是不好的做法，因為 enums 是 immutable (不可變的)。
{% endhint %}

### 範例 – \_\_init\_\_

***

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

{% code title="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
```

{% endcode %}

{% code title="PYTHON" %}

```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
```

{% endcode %}

## Functional API

***

`Enum` 函數 API 允許您創建 enumeration 類型，這些類型基本上是一組值的符號名稱。

{% code title="PYTHON" %}

```python
Enum(
    value='NewEnumName',
    names=<...>, *,
    module='...',
    qualname='...',
    type=<mixed-in class>,
    start=1)
```

{% endcode %}

<table><thead><tr><th width="170">參數</th><th>說明</th></tr></thead><tbody><tr><td><strong>value</strong></td><td>新 enumeration 的名稱。</td></tr><tr><td><strong>names</strong></td><td>enum members。這可以是 String、mapping、 names iterator 或 (name, value) pairs iterator。 這也可以是空格或逗號分隔的 String（除非另有說明，值將從 1 開始）</td></tr><tr><td><strong>module</strong></td><td>用作 enum 的 <code>__module__</code> 屬性。對於 pickling 和 introspection 很有用。</td></tr><tr><td><strong>qualname</strong></td><td>用作 enum 的 <code>__qualname__</code> 屬性。對於 introspection 很有用。</td></tr><tr><td><strong>type</strong></td><td>用作 Mixed-in Class。即，它定義 enumeration 的特定行為。 如果您希望 enum members 表現得像整數、Strings 等，這會很有用。</td></tr><tr><td><strong>start</strong></td><td>定義 enum members 自動編號的起始編號。</td></tr></tbody></table>

{% hint style="info" %}
**`Enum` 函數式 API 靈活且用途廣泛，使您能夠創建具有不同行為的複雜 enumeration 類型。**
{% endhint %}

{% hint style="warning" %}
**如果未提供 `module`，並且 Enum 無法確定它是什麼，則新的 Enum members 將不會 unpicklable； 為了使錯誤更接近 source，pickling 將被禁用。**
{% endhint %}

{% code title="PYTHON" %}

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

{% endcode %}

{% code title="PYTHON" %}

```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
```

{% endcode %}

\ <br>
