天天看點

enum -- 枚舉(三)

前情提示: 測試代碼中,右尖括号(

>

)表示指令行中輸入的指令; 單獨一行并以井字元(

#

)開頭的為輸出内容; 庫的導入僅在本文的第一個測試代碼中展現,其他代碼塊均省略庫的導入代碼。

  • 系統類型:

    Windows 10

  • python 版本:

    Python 3.9.0

前兩篇文章詳解了枚舉子產品中的四個枚舉類和自定義枚舉類及其相關内容,沒看過的小夥伴可以通過傳送門點選進入前兩篇文章閱讀。枚舉子產品的最後一篇來更加深入的了解一下比較深入并且不常用的一些知識點。

傳送門

enum – 枚舉(一)

enum – 枚舉(二)

enum – 枚舉(三)

不重要的枚舉成員的值

在某些場景中,人們并不關心枚舉成員的值是什麼,可以使用下列幾種方法定義枚舉:

  • 使用

    enum.auto()

    函數作為枚舉成員的值
  • 使用

    object()

    作為枚舉成員的值
  • 使用描述性的字元作為枚舉成員的值,同時做到了可進一步解釋此枚舉成員
  • 使用空元組作為值,并在自定義的

    __new__()

    中重新定義枚舉成員的值(隻要不重複即可)

看完以上的列舉,這種實作這種需求并不局限于上面幾種方法,隻要最終枚舉成員的值不重複即可,比如自定義一個随機生成字元串的函數。

import enum
import pickle  # 封存


'''enum.auto()'''
class TestA(enum.Enum):
    A = enum.auto()
    B = enum.auto()

'''object()'''
class TestB(enum.Enum):
    A = object()
    B = object()

'''描述字元串'''
class TestC(enum.Enum):
    A = '字母A'
    B = '字母B'

'''元組, 并自定義 __new__()'''
class TestD(enum.Enum):
    A = ()
    B = ()

    def __new__(cls, *args):
        '''擷取目前枚舉成員數并加一, 将結果指派給新定義的枚舉成員'''
        value = len(cls.__members__) + 1
        obj = object.__new__(cls)  # 必須建立一個枚舉成員對象
        obj._value_ = value
        return obj  # 必須傳回一個枚舉成員對象

print(list(TestA))
# [<TestA.A: 1>, <TestA.B: 2>]
print(list(TestB))
# [<TestB.A: <object object at 0x0000023986178210>>, <TestB.B: <object object at 0x0000023986178220>>]
print(list(TestC))
# [<TestC.A: '字母A'>, <TestC.B: '字母B'>]
print(list(TestD))
# [<TestD.A: 1>, <TestD.B: 2>]
           

封存

枚舉可以被封存和解封:

class Test(enum.Enum):
    A = enum.auto()
    B = enum.auto()

封存的枚舉成員A = pickle.dumps(Test.A)
解封的枚舉成員A = pickle.loads(封存的枚舉成員A)

print(封存的枚舉成員A)
# b'\x80\x04\x95\x1b\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04Test\x94\x93\x94K\x01\x85\x94R\x94.'
print(解封的枚舉成員A)
# Test.A
print(Test.A is 解封的枚舉成員A)  # 解封後的資料與原資料是否一緻
# True
           

功能性API

Enum

類屬于可調用對象,也就是說

Enum

類可以像函數一樣被調用:

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

參數:
    value: str, 枚舉的名稱
    names: 枚舉成員們的名稱, 可使用多種方式設定枚舉成員
    module: 關鍵字參數, str 或 None, 指明所在的子產品
    qualname: 關鍵字參數, str, 指明所在的子產品中的具體位置
    type: 關鍵字參數, 指明枚舉類的類型
    start: 關鍵字參數, int, 枚舉成員的起始值, 預設為 1
傳回值:
    枚舉
           

names

參數可以傳入一個以空格或逗号隔開的字元串,分隔的子字元串就是枚舉成員的名稱,各枚舉成員的值按順序自增,起始值由

start

參數設定,起始值預設為

1

names

參數也可以傳入疊代器或映射。

'''以空格分隔'''
TestA = enum.Enum('TestEnum', 'A B C D')
print(list(TestA))
# [<TestEnum.A: 1>, <TestEnum.B: 2>, <TestEnum.C: 3>, <TestEnum.D: 4>]

'''以空格分隔, 設定起始值為10'''
TestB = enum.Enum('TestEnum', 'A B C D', start=10)
print(list(TestB))
# [<TestEnum.A: 10>, <TestEnum.B: 11>, <TestEnum.C: 12>, <TestEnum.D: 13>]

'''傳入清單設定枚舉成員, 枚舉成員的值按順序自增, 起始值由 start 參數設定'''
TestC = enum.Enum('TestEnum', ['A', 'B', 'C', 'D'])
print(list(TestC))
# [<TestEnum.A: 1>, <TestEnum.B: 2>, <TestEnum.C: 3>, <TestEnum.D: 4>]

'''傳入清單, 并且元素格式為 ('名稱', '值')'''
TestD = enum.Enum('TestEnum', [('A', 11), ('B', 22), ('C', 33), ('D', 44)])
print(list(TestD))
# [<TestEnum.A: 11>, <TestEnum.B: 22>, <TestEnum.C: 33>, <TestEnum.D: 44>]

'''傳入映射, 格式為 {名稱: 值}'''
TestE = enum.Enum('TestEnum', {'A': 11, 'B': 22, 'C': 33, 'D': 44})
print(list(TestE))
# [<TestEnum.A: 11>, <TestEnum.B: 22>, <TestEnum.C: 33>, <TestEnum.D: 44>]
           

module

參數需要傳入一個子產品,為了在進行封存操作時成功執行。若指定一個錯誤的子產品,那麼封存操作将報錯。若參數值若設定為

None

__name__

最終指向的子產品均為目前檔案

__main__

'''module 參數預設為 None'''
TestA = enum.Enum('TestA', 'AAA BBB CCC')
print(pickle.loads(pickle.dumps(TestA)))  # 封存+解封
# <enum 'TestA'>

'''module 參數設定為 __name__'''
TestB = enum.Enum('TestB', 'AAA BBB CCC', module=__name__)
print(pickle.loads(pickle.dumps(TestB)))
# <enum 'TestB'>

'''module 參數設定為一個不存在的子產品'''
TestD = enum.Enum('TestD', 'AAA BBB CCC', module='aaa')
print(pickle.loads(pickle.dumps(TestD)))
# _pickle.PicklingError: Can't pickle <enum 'TestD'>: import of module 'aaa' failed
           

qualname

參數是指明在子產品中的具體位置,同

module

參數類似,設定這個參數的目的也是為了封存操作,

pickle

協定版本

4

在某些情況下需要依賴設定的具體位置。

布爾值

枚舉類的布爾值總是

True

,枚舉中的枚舉成員的布爾值也總是

True

。 枚舉成員的布爾值與枚舉成員的值無關,如果想要以枚舉成員的值來計算布爾值,可以修改

__bool__()

魔法方法。

'''不修改 __bool__() 魔法方法的枚舉類'''
class Test(enum.Enum):
    A = 0
    B = None

print(bool(Test))
# True
print(bool(Test.A))
# True
print(bool(Test.B))
# True

'''修改 __bool__() 魔法方法的枚舉類'''
class Test(enum.Enum):
    A = 0

print(bool(Test.A))
# False
           

支援枚舉類使用的屬性

__members__

是一個

member_name:member

條目的隻讀有序映射。得到的結果是以

{名稱: 枚舉成員對象}

為結構的字典。

class Test(enum.Enum):
    A = 1
    B = 2
    C = 1

print(Test.__members__)
# {'A': <Test.A: 1>, 'B': <Test.B: 2>, 'C': <Test.A: 1>}
           

支援枚舉成員使用的屬性

  • _name_

    _value_

    分别傳回枚舉成員的名稱和值;
  • _generate_next_value_

    在功能性API中被使用,為枚舉成員擷取适當的值,也可被列印;
  • _missing_

    作用是當未發現某個值時所使用的查找函數;
  • _ignore_

    是一個名稱清單,結果可以是

    list

    ,也可以是

    str

    ,不會轉化為枚舉成員,并将從最終類中被移除;
  • _order_

    Python2

    的遺留屬性,在

    Python2

    中負責記錄枚舉成員的定義順序;
'''可直接列印的屬性'''
class Test(enum.Enum):
    A = 1
    B = 2
    C = 1

print(Test.A._name_)
# 'A'
print(Test.A._value_)
# 1
print(Test.A._generate_next_value_)
# <bound method Enum._generate_next_value_ of <Test.A: 1>>

'''_ignore_的用法'''
class Period(enum.Enum):
    _ignore_ = 'Period i'
    Period = vars()
    for i in range(3):
        Period['obj_%d' % i] = i

print(list(Period))
# [<Period.obj_0: 0>, <Period.obj_1: 1>, <Period.obj_2: 2>]
           

公衆号 : 「python雜貨鋪」,專注于 python 語言及其相關知識。發掘更多原創文章,期待您的關注。

enum -- 枚舉(三)

參考資料

官方文檔: https://docs.python.org/zh-cn/3/library/enum.html

源代碼: Lib/enum.py