Python 標準ライブラリ enum 列挙型
列挙型enumを使うと、カテゴリーに整数や文字列等の識別子を付けて適切に区別できるようになる。
enumの宣言
クラスEnumを継承しメンバーを定義することで列挙型を宣言できる。
from enum import Enum
class Animal(Enum):
DOG = 1
CAT = 2
SNAKE = 3
Animal # => <enum 'Animal'>
list(Animal) # =>[<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.SNAKE: 3>]
他にEnumに空白区切りの文字列、リスト、辞書、タプルのリスト等を引数で渡すことでも列挙を定義できる。
MARK = Enum('MARK', 'SPADE HEART DIAMOND CLUB')
MARK = Enum('MARK', ['SPADE', 'HEART', 'DIAMOND', 'CLUB' ])
MARK = Enum('MARK', {'SPADE':1, 'HEART':2, 'DIAMOND':3, 'CLUB':4 })
MARK = Enum('MARK', [('SPADE',1), ('HEART',2), ('DIAMOND',3), ('CLUB',4) ])
MARK # => <enum 'MARK'>
list(MARK) # => [<MARK.SPADE: 1>, <MARK.HEART: 2>, <MARK.DIAMOND: 3>, <MARK.CLUB: 4>]
enumの使い方
列挙の型.メンバーの名称
や列挙の型(インデックス)
、列挙の型[メンバーの名称]
で
列挙型各要素にアクセスできる。
Animal(1) # => <Animal.DOG: 1>
Animal.CAT # => <Animal.CAT: 2>
Animal['SNAKE'] # = > <Animal.SNAKE: 3>
printやreprで列挙の情報を表示できる。
print(Animal.DOG) # => Animal.DOG
repr(Animal.CAT) # => '<Animal.CAT: 2>'
列挙はイテレートできる。
for a in Animal:
print(a)
list(Animal) # => [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.SNAKE: 3>]
[a.name for a in Animal] # => ['DOG', 'CAT', 'SNAKE']
[key for key in Animal.__members__.keys()] # => ['DOG', 'CAT', 'SNAKE']
[a.value for a in Animal] # => [1, 2, 3]
[value for value in Animal.__members__.values()] # => [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.SNAKE: 3>]
[(name, value) for name, value in Animal.__members__.items()]
# => [('DOG', <Animal.DOG: 1>), ('CAT', <Animal.CAT: 2>), ('SNAKE', <Animal.SNAKE: 3>)]
列挙は定義した型、および、Enumのサブクラスになっている。
type(Animal.SNAKE) # => <enum 'Animal'>
isinstance(Animal.DOG, Enum) # => True
isinstance(Animal.DOG, Animal) # => True
issubclass(type(Animal.DOG), Animal) # => True
issubclass(type(Animal.DOG), Enum) # => True
名前、値にはそれぞれname
、value
でアクセスできる。
Animal.CAT.name # => 'CAT'
Animal.CAT.value # => 2
列挙同士は比較可能、整数値との比較はFalseになる。
Animal.DOG == Animal.DOG # => True
Animal.DOG != Animal.DOG # => False
Animal.DOG == Animal.CAT # => False
Animal.DOG != Animal.CAT # => True
Animal.DOG is Animal.DOG # => True
Animal.DOG is not Animal.DOG # => False
Animal.DOG is Animal.CAT # => False
Animal.DOG is not Animal.CAT # => True
Animal.DOG == 1 # => False
一意を保証する列挙
Enumは同じ値のメンバーを定義してもそのままではエラーとならない。
アノテーション@unique
で一意でない定義を行うとエラーとする事ができる。
from enum import Enum, unique
class EnumSample(Enum):
AAA = 1
BBB = 2
CCC = 2
@unique
class EnumSample(Enum):
AAA = 1
BBB = 2
CCC = 2
# => ValueError: duplicate values found in <enum 'EnumSample'>: CCC -> BBB
自動採番auto
autoを使うと自動で値の採番を行う事ができる。
from enum import Enum, auto
class EnumSample(Enum):
AAA = auto()
BBB = auto()
CCC = auto()
list(EnumSample) # => [<EnumSample.AAA: 1>, <EnumSample.BBB: 2>, <EnumSample.CCC: 3>]
整数を値にもつ列挙 IntEnum
整数を値に持ち、整数との直接比較ができる列挙型としてIntEnumが提供されている。
from enum import IntEnum
class Animal(IntEnum):
DOG = 1
CAT = 2
SNAKE = 3
Animal.DOG == 1 # => True
Animal.DOG != 2 # => True
int(Animal.SNAKE) # = > 3
整数フラグの列挙 IntFlag
整数の値もったフラグ用途の列挙としてIntFlagが提供されている。
値を各桁のビットで表現し、ビット演算|
で値を定義するとOR(または)の意味で使うことができる。
from enum import IntFlag
class Days(IntFlag):
MONDAY = 0b0000001
TUESDAY = 0b0000010
WEDNESDAY = 0b0000100
THURSDAY = 0b0001000
FRIDAY = 0b0010000
SATURDAY = 0b0100000
SUNDAY = 0b1000000
WEEKEND = 0b1100000
monday_or_tuesday = Days.MONDAY | Days.TUESDAY
monday_or_tuesday # => <Days.TUESDAY|MONDAY: 3>
monday_or_tuesday = Days.MONDAY + Days.TUESDAY
monday_or_tuesday # => <Days.TUESDAY|MONDAY: 3>
bool(Days.MONDAY & monday_or_tuesday) # => True
bool(Days.WEDNESDAY & monday_or_tuesday) # => False
bool(Days.SUNDAY & Days.WEEKEND) # => True
Flagの列挙 Flag
Flag用途の列挙としてFlagが提供されている。 autoを組み合わせる事で内部の値を意識しないでフラグとして使える列挙を定義できる。
from enum import Flag, auto
class Days(Flag):
MONDAY = auto()
TUESDAY = auto()
WEDNESDAY = auto()
THURSDAY = auto()
FRIDAY = auto()
SATURDAY = auto()
SUNDAY = auto()
WEEKEND = SUNDAY | SUNDAY
monday_or_tuesday = Days.MONDAY | Days.TUESDAY
monday_or_tuesday # => <Days.TUESDAY|MONDAY: 3>
bool(Days.MONDAY & monday_or_tuesday) # => True
bool(Days.WEDNESDAY & monday_or_tuesday) # => False
bool(Days.SUNDAY & Days.WEEKEND) # => True
文字列を値に持った列挙
列挙の値は数値に限定されない。文字列を値として定義することもできる。
class Animal(Enum):
DOG = 'd'
CAT = 'c'
SNAKE = 's'
Animal.DOG # => <Animal.DOG: 'd'>
Animal['DOG'] # => <Animal.DOG: 'd'>
Animal('d') # => <Animal.DOG: 'd'>
Animal.CAT.value # => 'c'
Animal.SNAKE.name # => 'SNAKE'
自動インクリメントの列挙
__new__
で列挙の値が新たに定義されるときの挙動を指定できる。
メンバーの数で値valueを振る事で、値がインクリメントする列挙を定義できる。
class AutoNumber(Enum):
def __new__(cls, *args):
value = len(cls.__members__) + 1
obj = object.__new__(cls)
obj._value_ = value
return obj
class AutoSequential(AutoNumber):
AAA = ()
BBB = ()
CCC = ()
list(AutoSequential) # => [<AutoSequential.AAA: 1>, <AutoSequential.BBB: 2>, <AutoSequential.CCC: 3>]
独自のメンバーを持った列挙
__init__
で普通のクラスと同じように初期化時の設定を行える。
class Department(Enum):
ACCOUNTING = (10, '経理')
GENERALAFFAIRS = (20, '総務')
Sales1 = (31, '営業1部')
Sales2 = (32, '営業2部')
def __init__(self, id, department_name):
self.id = id
self.department_name = department_name
Department.ACCOUNTING # => <Department.ACCOUNTING: (10, '経理')>
Department.ACCOUNTING.name # => 'ACCOUNTING'
Department.ACCOUNTING.id # => 10
Department.ACCOUNTING.department_name # => '経理'