ikeikeikeike's unk blog.

http://github-awards.com/users/ikeikeikeike

Python Enum

Enumすら思い出せない忘れんぼさんなんで PythonEnum を弄ってみました

列挙型定義

from enum import Enum

class Colors(Enum):
    RED = '1'
    BLUE = 2
    GREEN = 'green'

print(Colors)  # <enum 'Colors'>
動的に
>>> Enum('Colors', (('RED', '1'), ('BLUE', 2), ('GREEN', 'green')))
<enum 'Colors'>
Enum型の一覧
>>> Colors.__members__
mappingproxy(OrderedDict([('RED', <Colors.RED: '1'>), ('BLUE', <Colors.BLUE: 2>), ('GREEN', <Colors.GREEN: 'green'>)]))
名前、値を得る
>>> Colors.RED
<Colors.RED: '1'>
>>> Colors['RED']
<Colors.RED: '1'>
>>> Colors.RED.name
'RED'
>>> Colors.RED.value
'1'
iterを当てるとgeneratorが返る
>>> iter(Colors)
<generator object <genexpr> at 0x108b12120>
>>> 
>>> (Colors.__members__[name] for name in Colors.__members__)
<generator object <genexpr> at 0x108b12438>
>>>
>>> for color in Colors:
...    print(repr(color))
...
<Colors.RED: 1>
<Colors.BLUE: 2>
<Colors.GREEN: 3>
定義後はClass, Attributeは削除できない
>>> del Colors.RED
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: RED
>>> 
>>> del Colors.RED.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/python/lib/python3.4/enum.py", line 29, in __delete__
    raise AttributeError("can't delete attribute")
AttributeError: can`t delete attribute
>>>
>>> del Colors.RED.value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/python/lib/python3.4/enum.py", line 29, in __delete__
    raise AttributeError("can't delete attribute")
AttributeError: can`t delete attribute
辞書のキーとして使う、Enumの比較

__hash__が定義されてたので辞書のキーでも使えた

>>> red1 = Colors.RED
>>> dct = {red1: 10}
>>> dct[red1]
10
>>> red2 = Colors.RED
>>> dct[red2]
10
>>> red1 == red2
True
Pickle化

__getnewargs__ がある, pickleable みたい

>>> from pickle import dumps, loads
>>> Colors.RED == loads(dumps(Colors.RED))
True

Enumの型を指定して扱う

Enumは定義時に型を指定すると列挙する値が、すべて指定した型になる

strとして列挙したい場合
from enum import Enum

class Colors(str, Enum):
    RED = '1'
    BLUE = 2
    GREEN = 'green'

print(repr(Colors.BLUE))  # <Colors.BLUE: '2'>
print(repr(Colors.BLUE.value))  # '2'
intとして列挙したい場合

IntEnumが用意されている

下記では 'green' がエラーになる

from enum import IntEnum

class Colors(IntEnum):
    RED = '1'
    BLUE = 2
    GREEN = 'green'  #  ValueError: invalid literal for int() with base 10: 'green'

isdigitな数値ならOKのようだ、isnumericはだめ(IVとか, 四とか)

from enum import Enum

class Colors(int, Enum):
    RED = '1'
    BLUE = 2
    GREEN = b'3'  
    YELLOW = '4'

print(repr(Colors.GREEN.value))  # 3
print(repr(Colors.YELLOW.value))  # 4
floatとして列挙したい場合
from enum import Enum

class Colors(float, Enum):
    RED = '1'
    BLUE = 2
    GREEN = b'3'
    YELLOW = '4'

print(repr(Colors.GREEN.value))  # 3.0
print(repr(Colors.YELLOW.value))  # 4.0
tupleとして列挙したい場合

もちろんtupleもある

from enum import Enum

class Colors(tuple, Enum):
    RED = (1, 'red color')
    BLUE = (2, 'blue color')
    GREEN = (3, 'green color')

print(repr(Colors.RED))  # <Colors.RED: (1, 'red color')>
print(repr(Colors.RED.value))  # (1, 'red color')
NamedInt
class Colors(NamedInt, Enum):
    RED = ('red color', 1)
    BLUE = ('blue color', 2)
    GREEN = ('green color', 3)

print(repr(Colors.RED))  # <Colors.RED: NamedInt('red color', 1)>
print(repr(Colors.RED.value))  # NamedInt('red color', 1)
OrderedEnum

Eum同士の比較が可能

class Colors(OrderedEnum, Enum):
    RED = 1
    BLUE = 2
    GREEN = 3

print(Colors.RED < Colors.BLUE)  # True
class Colors(Enum):
    RED = 1
    BLUE = 2
    GREEN = 3

print(Colors.RED < Colors.BLUE)  # TypeError: unorderable types: Colors() < Colors()
LabelledIntEnum
class LabelledIntEnum(int, Enum):
    def __new__(cls, *args):
        value, label = args
        obj = int.__new__(cls, value)
        obj.label = label
        obj._value_ = value
        return obj

class Colors(LabelledIntEnum):
    RED = (1, "red")
    BLUE = (2, "blue")
    GREEN = (3, "green")

print(repr(list(Colors)))  # [<Colors.RED: 1>, <Colors.BLUE: 2>, <Colors.GREEN: 3>]
print(repr(Colors(1)))  # <Colors.RED: 1>
print(repr(Colors.RED))  # <Colors.RED: 1>
print(repr(Colors.RED.value))  # 1
UniqueEnum

下のuniqueデコレーターと同じかな

列挙する値のユニークを保証する

uniqueデコレーターがありました。つかいませう

from enum import (
    Enum, 
    unique
)

@unique
class Colors(int, Enum):
    RED = '1'
    BLUE = 2
    GREEN = '3'
    YELLOW = '3'  # ValueError: duplicate values found in <enum 'Colors'>: YELLOW -> GREEN

自動採番

値がなければナンバリングされる

int
>>> Enum('Colors', ('RED', 'BLUE', 'GREEN', ), module=__name__).RED
<Colors.RED: 1>
>>> Enum('Colors', 'RED BLUE GREEN').RED
<Colors.RED: 1>
str
>>> StrEnum('Colors', 'RED BLUE GREEN').RED
<Colors.RED: '1'>
tuple
>>> TupleEnum('Colors', 'RED BLUE GREEN').RED
<Colors.RED: (1,)>
AutoNumberInAList
class AutoNumberInAList(Enum):
    def __new__(cls):
        value = [len(cls.__members__) + 1]
        obj = object.__new__(cls)
        obj._value_ = value
        return obj

class Colors(AutoNumberInAList):
    RED = ()
    BLUE = ()
    GREEN = ()

print(repr(Colors.RED))  # <Colors.RED: [1]>
print(repr(Colors.RED.value))  # [1]
AutoNumber

定義時に自動採番

auto_enum

定義時のmetaclassで自動採番

終わり

Enumには夢が詰まっているとのこと