iT邦幫忙

1

[ Python雜記] 那些Enum的未知與妙用

  • 分享至 

  • xImage
  •  

有時候在改code的時候看到一些狀態回傳都使用Enum,一開始覺得理所當然,但直到前陣子看到一些文章在細究Enum才知道原來這個套件真的是妙用之大。

下面有一個簡單的例子,習慣上會把Enum Member Name都寫成全大寫。

from enum import Enum

# 簡單的水果範例
class Fruit(Enum):
  APPLE = "Apple"
  BANANA = "Banana"
  ORANGE = "Orange"

當然,上面舉的範例有夠爛。但這樣上面狀態回傳水果時就可以使用下面的方式直接寫下面這樣

def get_fruit(....)
  ...
  return Fruit.APPLE.name

這樣寫有什麼好處?

  • 所有相關的數值都可以整理在一起,不用再另寫文件紀錄
  • Enum在大部分IDE裡面都可以被自動補全拼字,不用擔心自己打錯字
  • 在可讀性上跟維護性上都會比起沒紀錄狀態來得方便。

而工作時,有些同事在Table也只會存取相對應的數字,最後才回到程式中轉換

from enum import Enum

class Status(Enum):
  Open = 1
  Pending = 2
  Close = 3
  

這樣使用下面的方式就可以直接再轉回狀態了。讓整體狀態方便管理也容易記憶跟撰寫。

from enum import Enum

def process_status(....):
  ....
  return Status(1).name

Auto的自動轉換

以為這樣已經夠神奇了,但前陣子看到另外一個更好玩的寫法。下面這種寫法就會直接把數字順序的補下去了。

from enum import Enum, auto

class EmployerNumber(Enum):
    ANDY = auto() # 1
    SANDY = auto() # 2
    WENDY = auto() # 3
    CINDY = auto() # 4
    MANDY = auto() # 5

print(list(EmployerNumber))

# [<EmployerNumber.Andy: 1>, <EmployerNumber.Sandy: 2>, 
# <EmployerNumber.Wendy: 3>, <EmployerNumber.Cindy: 4>, 
# <EmployerNumber.Mandy: 5>]

Enum看到現在,轉換也有幾種寫法。看完也是覺得寫法千變萬化。

class EmployerNumber(Enum):
    ANDY = auto() # 1
    SANDY = auto() # 2
    WENDY = auto() # 3
    CINDY = auto() # 4
    MANDY = auto() # 5

print(EmployerNumber.ANDY.name) # ANDY
print(EmployerNumber['ANDY'].name) # ANDY
print(EmployerNumber(1).name) # ANDY

print(EmployerNumber.SANDY.value) # 2
print(EmployerNumber['SANDY'].value) # 2
print(EmployerNumber(2).value) # 2

StrEnum

若當你確定你的Enum轉出來的Value會是String就可以採用下面寫法,就不用透過value再轉一層,甚至直接可以接String method轉換。(但要3.11之後的版本才能使用)

from enum import StrEnum

class Fruit(StrEnum):
  APPLE = "Apple"
  BANANA = "Banana"
  ORANGE = "Orange"

print(Fruit.APPLE) # Apple
print(Fruit.APPLE.upper()) # APPLE

3.11之前的寫法就可以採用下列

from enum import Enum

class Fruit(str, Enum):
  APPLE = "Apple"
  BANANA = "Banana"
  ORANGE = "Orange"

print(Fruit.APPLE) # Apple
print(Fruit.APPLE.upper()) # APPLE

IntEnum用途

不像StrEnum,IntEnum不受版本使用限制,也可以很方便的轉換數字

from enum import IntEnum

class EmployerNumber(IntEnum):
    ANDY = auto() # 1
    SANDY = auto() # 2
    WENDY = auto() # 3
    CINDY = auto() # 4
    MANDY = auto() # 5

print(EmployerNumber.ANDY) # 1

Decorator : Unique、CONTINUOUS 與Global

這三者中,前兩者我覺得會是很實用的一些裝飾器的用法,而Global的用法可能就要小心取用。

  • unique
    unique可以避免在同一個Enum中有重複的value
from enum import Enum, unique

@unique
class Students(Enum):
    MANDY = 1
    CHARLIE = 1
    JOHN = 2
    SALLY = 3
    SNOOPY = 4

"""ValueError: duplicate values found in <enum 'Students'>: CHARLIE -> MANDY
"""
  • Continous
    Continous則可以確保你的value輸入時是有順序的,沒有跳號
from enum import Enum, verify, CONTINUOUS

@verify(CONTINUOUS)
class EmployerNumber(Enum):
    ANDY = 1
    SANDY = 2
    CINDY = 4
    MANDY = 5

"""ValueError: invalid enum 'EmployerNumber': missing values 3
"""
  • Global

而Global更為有趣,這樣的裝飾器讓你可以直接呼叫Enum 成員的Name,但這樣用起來可能會有誤用或難以閱讀的狀況,可能都要小心使用。

from enum import Enum, global_enum

@global_enum
class EmployerNumber(Enum):
    ANDY = 1
    SANDY = 2
    CINDY = 4
    MANDY = 5

print(ANDY) # ANDY
print(ANDY.value) # 1

感覺Enum還是有很多神奇的用法,就大概看了一些覺得工作上會用到的東西摘出來寫就是。就當作自己工作上跟閱讀上的筆記來做紀錄,也方便之後翻閱時方便找資料。

參考資料:
Enum (枚舉),程式可讀性提高必備技巧
Module enum overview
Python 3 文件


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言