enum — 枚舉型態 — 你所不知道的 Python 標準函式庫用法 07

enum – Support for enumerations

An enumeration is a set of symbolic names (members) bound to unique, constant values. Within an enumeration, the members can be compared by identity, and the enumeration itself can be iterated over.

官方介紹文件:8.13. enum — Support for enumerations

enum 是 Python 裏用來建立枚舉形態的標準函式庫。enum 算是比較新的標準函式庫,學習 enum 可以讓你輕鬆建立枚舉,改寫以前單獨使用 const variable 的狀況。

01. Quickstart Tutorial

從今天開始,讓我們把這樣枚舉的 Code:

使用 enum 來改寫:

之後就可以改用 enum 來比對型態:

透過 enum member 可以取得 name 或是 value:

透過 enum class 可以取得 enum member:

不同的 enum class 雖然有相同的 enum value,但比較結果是不相同的

 

“可是我有 legacy code 啊,改成使用 enum 就壞掉了”

沒關係,透過 globals() 就可以 hack 過去了:

其實應該要透過 globals() + IntEnum 才能直接將 enum member 當 int 用:

真是可喜可賀,可喜可賀。透過改寫枚舉方式,我們邁向現代化 Python 更進一步了。

02. HOW-TO Guides

使用 IntEnum 來簡化整數枚舉比對

透過 IntEnum 我們可以讓整數枚舉的比對變得更輕鬆一點:

此時不同 enum class 的比較會是相等的:

透過繼承來組合出不同的 default enum (e.g. StrEnum)

我們可以透過繼承來達到前面 IntEnum 的效果,例如說要製作 StrEnum:

透過 IntFlag 來進行 bitwise 操作:

如果是 IntFlag,執行 bitwise 操作 (&, |, ^, ~),回傳結果還會是 IntFlag 成員。如果是其他操作則會回傳 int

快速的創造 enum class

03. Discussions

PEP 435 – Status of discussions

枚舉型態的想法並不是第一次出現在 Python 討論之中,在 2005 年 PEP 354 有嘗試過一次而被拒絕。近期則在 Python-ideas 開啟了一組新的討論。許多新的點子在一連串的討論中被提出。經過一長串的討論後,Guido 提議將 flufl.enum 加入標準函式庫。在 Python 2013 language summit 之中這個議題被深入的討論。討論中許多的開發者希望 enum 能夠繼承 int,讓我們可以取代標準函式庫中許多的整數枚舉而不必影響到 backword compatibility。之後的討論讓開發者們提議加入 IntNum 這個特殊型態的 Enum

Enum 以及 IntEnum 討論的關鍵點在於,這樣與整數的比較在語意上是否具有意義。對於大多數的枚舉,拒絕與整數比較是一個 feature。可以與整數比較的 enums 會讓其可以與其他不相關的型態比較,這在多數的狀況下是不希望發生的。不過某些情況下,例如說 socket.AF_INET ,透過 IntEum 可以直接替換掉。

之後在 2013 年4月底的討論,enumeration members 的型態需要與 enum 相同: type(Color.red) == Color。Guido 在這個議題上做出了決定,另外也對 enum 不能 subclass (除非 subclass 沒有定義新的 enumration members) 這件事情做出了決定。

這個 PEP 在 20130510 被 Guido 所接受。

Enum 實作? Enum 的 metaclass “EnumMeta”?

Enum 在定義與實作上有著諸多的限制以及創意。限制在於多處,例如不能夠使用多個 mixin_type、mixin_type 繼承時位置有限制需要在第一個、enum member 名稱不能使用 mro、創立後不能夠被繼承、如果要繼承則不能有 enum member 等等。創意在於透過 mixin_type,enum member 能夠直接比較相對應的型態、enum member 的值能夠是 object 、 None 同時會自動處理對應數值等。

這些如同魔術般的創意與限制,在 Python 如果要實作,就必定會要談到 metaclass。在這邊僅提點基本的概念:透過 metaclass EnumMeta,當創立繼承 enum.Enum 的 enum class (e.g. Animal(enum.Enum)),就會觸發EnumMeta.__new__ 檢查以及設立這些規則與結果。之後使用 Animal 建立實例的時候就可以使用這些功能。

請參考程式碼:EnumMetaEnum ,以及官方文件:Datamodel – metaclass

How metaclass work?

這根本可以開專文了。請先參考 Stackoverflow 這篇文章

04. References

Leave a reply:

Your email address will not be published.