python模塊之enum_上

enum模塊定義了:python

  • 4種枚舉類:Enum, IntEnum, Flag, IntFlag
  • 裝飾器:unique()
  • 助手:auto

Flag, IntFlag, auto在python3.6中加入app

建立枚舉

from enum import Enum
class Color(Enum):
    RED = 2
    GREEN = 4
    BLUE = 6

注意點:
1. 枚舉值能夠是任何類型,若是值不重要可使用auto()自動選擇。但在有其餘已定義的值的狀況下,謹慎與auto混用
2. Color是枚舉類,Color.RED等是枚舉成員,枚舉成員擁有name和value屬性
3. 雖然使用class關鍵字建立,但枚舉並非常規意義上的python類spa

枚舉成員的展示形式:3d

>>>print(Color.RED)
Color.RED

>>>print(repr(Color.RED))
<Color.RED: 2>

枚舉成員的type類型是其所屬的枚舉類:code

>>>type(Color.RED)
<enum 'Color'>
>>>isinstance(Color.RED, Color)
True

枚舉支持按照定義時的順序進行迭代:orm

>>>for color in Color:
...    print(color)
...
Color.RED
Color.GREEN
Color.BLUE

枚舉成員是可哈希的,所以能夠在字典和集合中使用:blog

>>> apples = {}
>>> apples[Color.RED] = 'red delicious'
>>> apples[Color.GREEN] = 'granny smith'
>>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}
True

對枚舉成員及其屬性的程序化訪問

經過值訪問枚舉成員:繼承

>>>Color(2)
<Color.RED: 2>

經過名稱訪問枚舉成員:圖片

>>>Color["RED"]
<Color.RED: 2>

獲取枚舉成員的名稱和值:ci

>>>member = Color.RED
>>>member.name
"RED"
>>>member.value
2

枚舉成員及其值的重複性問題

擁有兩個相同名稱的枚舉成員是不容許的:

>>> class Shape(Enum):
...     SQUARE = 2
...     SQUARE = 3
...
Traceback (most recent call last):
...
TypeError: Attempted to reuse key: 'SQUARE'

不過不一樣的枚舉成員容許擁有相同的值。後定義的成員是先定義的成員的別名,經過值或名稱訪問時都將返回先定義的成員:

>>> class Shape(Enum):
...     SQUARE = 2
...     DIAMOND = 1
...     CIRCLE = 3
...     ALIAS_FOR_SQUARE = 2
...
>>> Shape.SQUARE
<Shape.SQUARE: 2>
>>> Shape.ALIAS_FOR_SQUARE
<Shape.SQUARE: 2>
>>> Shape(2)
<Shape.SQUARE: 2>

注意點:任意兩個枚舉屬性(包括成員、方法等)不容許存在相同的名稱

枚舉值惟一約束

默認狀況下,容許多個成員擁有相同的值。使用unique裝飾器能夠對枚舉值進行惟一約束

@enum.unique: 枚舉專用的類裝飾器。它在枚舉的__members__屬性中只要查找到成員別名就拋出ValueError異常

>>> from enum import Enum, unique
>>> @unique
... class Mistake(Enum):
...     ONE = 1
...     TWO = 2
...     THREE = 3
...     FOUR = 3
...
Traceback (most recent call last):
...
ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE

自動生成枚舉值

對於不重要的枚舉值,可使用auto自動生成:

>>> from enum import Enum, auto
>>> class Color(Enum):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

auto生成什麼值取決於_generate_next_value_()方法,可重寫:

>>> class AutoName(Enum):
...     def _generate_next_value_(name, start, count, last_values):
...         return name
...
>>> class Ordinal(AutoName):
...     NORTH = auto()
...     SOUTH = auto()
...     EAST = auto()
...     WEST = auto()
...
>>> list(Ordinal)
[<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]

迭代

對枚舉成員的迭代,並不會包含成員別名:

>>> list(Shape)
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]

__members__屬性是一個映射了枚舉成員及其名稱的有序字典,包括成員別名:

>>> for name, member in Shape.__members__.items():
...     name, member
...
('SQUARE', <Shape.SQUARE: 2>)
('DIAMOND', <Shape.DIAMOND: 1>)
('CIRCLE', <Shape.CIRCLE: 3>)
('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)

>>> [name for name, member in Shape.__members__.items() if member.name != name]
['ALIAS_FOR_SQUARE']

枚舉比較(後兩種不適用於IntEnum)

>>> Color.RED is Color.RED
True

>>> Color.RED == Color.BLUE
False

>>> Color.RED < Color.BLUE
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Color' and 'Color'

>>> Color.BLUE == 6 # 與非枚舉的值進行等值比較老是返回False
False

容許的枚舉成員與屬性

枚舉是python類,也能夠擁有普通方法和特殊方法:

class Mood(Enum):
    FUNKY = 1
    HAPPY = 3

    def describe(self):
        # self is the member here
        return self.name, self.value

    def __str__(self):
        return 'my custom str! {0}'.format(self.value)

    @classmethod
    def favorite_mood(cls):
        # cls here is the enumeration
        return cls.HAPPY

注意點:若是枚舉中定義了__new()__或者__init__()方法,賦值給枚舉成員的值將被傳遞到__new()__或者__init__()

枚舉的繼承限制

自定義枚舉類必須繼承自一個枚舉基類,至多一個具體的數據類型以及0至多個混合類。繼承順序以下:

class EnumName([mix-in, ...,] [data-type,] base-enum):
    pass

基類枚舉若是已經定義了成員,則不能被任何子類繼承,以下第一種是不容許的,但第二種能夠:

>>> class MoreColor(Color):
...     PINK = 17
...
Traceback (most recent call last):
...
TypeError: Cannot extend enumerations
>>> class Foo(Enum):
...     def some_behavior(self):
...         pass
...
>>> class Bar(Foo):
...     HAPPY = 1
...     SAD = 2
...

不能這麼作的緣由是可能破壞某些重要的不容許改變的值(原話是would lead to a violation of some important invariants of bytes and instances)。

序列化

>>> from a.b import Color
>>> from pickle import dumps, loads
>>> Color.RED is loads(dumps(Color.RED))
True

通常要求序列化的枚舉要定義在模塊頂層,由於反序列化要求枚舉可以從模塊導入。不過在第4版的pickle協議中,已經能夠序列化嵌套在類中的枚舉

經過在枚舉中定義__reduce_ex__()方法,能夠修改枚舉成員的序列化/反序列化行爲

Functional API

枚舉類是可調用的:

>>> Animal = Enum("Pet", "Tortoise CAT DOG")

完整的API以下:
Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)
圖片描述

相關文章
相關標籤/搜索