Enumでvalue以外のkeyでも値を取得する方法
はじめに
多くのプログラミング言語にはEnumというものがあります。Pythonにも同様にあります。メンバーの取得はそれぞれのvalue
をkeyに取得できますが、それ以外の値をkeyにすることはできません。通常のEnumを拡張すればできたので紹介します。
通常のEnumの確認
まずは通常のEnumの利用方法を確認します。
>>> from enum import Enum
>>>
>>> class Color(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
# 上記のようにEnumを宣言すると
# 1や2といったvalueをkeyにして各メンバーにアクセスできます
>>> color = Color(1)
>>> print(color)
Color.RED
# もちろん直接アクセスすることもできます
>>> print(Color.RED)
Color.RED
>>> print(color == Color.RED)
True
やりたいこと
Color(1)
でColor.RED
にアクセスできましたがたとえばColor('red')
やColor('赤')
でもアクセスできたらEnum
の可能性が広がります。
>>> from enum import Enum
>>>
>>> class Color(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
# 以下のようにアクセスしようとするともちろんエラーになる
>>> color = Color('red')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python3.6/enum.py", line 293, in __call__
return cls.__new__(cls, value)
File "/usr/local/lib/python3.6/enum.py", line 535, in __new__
return cls._missing_(value)
File "/usr/local/lib/python3.6/enum.py", line 548, in _missing_
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 'red' is not a valid Color
>>> color = Color('赤')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python3.6/enum.py", line 293, in __call__
return cls.__new__(cls, value)
File "/usr/local/lib/python3.6/enum.py", line 535, in __new__
return cls._missing_(value)
File "/usr/local/lib/python3.6/enum.py", line 548, in _missing_
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: '赤' is not a valid Color
実装
ではkeyを拡張したEnumの実装を確認します。
# 宣言時に以下のように`_value2member_map_`を更新する
>>> from enum import Enum
>>>
>>> class Color(Enum):
... def __new__(cls, value, en, ja):
... obj = object.__new__(cls)
... obj._value_ = value
... cls._value2member_map_.update({en: obj, ja: obj})
... return obj
... RED = (1, 'red', '赤')
... GREEN = (2, 'green', '緑')
... BLUE = (3, 'blue', '青')
# これで先程のように'red'や'赤'でアクセスすると
>>> color = Color('red')
>>> print(color)
Color.RED
>>> red = Color('赤')
>>> print(red)
Color.RED
最後に
やりすぎるとkeyがかぶったりする可能性もありますが、知っておいて損はないと思います。
DBではint型、APIではstr型とかで使えそうです。