1はNORMAL, 2はWARNING、3は…
生データを読み込んだ時、状態を表す数字が入った列があったらどうしますか?
intとしてそのまま扱われた場合、こんなコードもあっさり通ってしまってバグの温床になっちゃいます。
df = pd.DataFrame()
df["status"] = [0, 1, 2]
df["value"] = [0, 1, 2]
df["status"] + df["some_value"]
# 0 0
# 1 2
# 2 4
# dtype: int64
対応する値と状態がわかってるなら、Enumにしちゃいましょう!
置き換えよう!
Enumを継承した自作クラスを用意し、クラスのコンストラクタに値を渡してやるとこの通り!
from enum import Enum
class Status(Enum):
NORMAL = 0
WARNING = 1
ERROR = 2
raw_status = [0, 1, 2]
status = [Status(v) for v in raw_status]
print(status)
# [<Status.NORMAL: 0>, <Status.WARNING: 1>, <Status.ERROR: 2>]
対応する値が文字列の場合もよしなにやってくれます。
from enum import Enum
class Status(Enum):
NORMAL = "NORMAL"
WARNING = "WARNING"
ERROR = "ERROR"
raw_status = ["NORMAL", "WARNING", "ERROR"]
status = [Status(v) for v in raw_status]
print(status)
# [<Status.NORMAL: 'NORMAL'>, <Status.WARNING: 'WARNING'>, <Status.ERROR: 'ERROR'>]
改めて冒頭のコードにチャレンジ。
Statusクラスとintはプラス演算子が使えませんよ!って怒ってくれてますね。
from enum import Enum
class Status(Enum):
NORMAL = 0
WARNING = 1
ERROR = 2
df = pd.DataFrame()
df["status"] = [0, 1, 2]
df["value"] = [0, 1, 2]
df["status"] = [Status(v) for v in df["status"]]
df["status"] + df["some_value"]
# TypeError: unsupported operand type(s) for +: 'Status' and 'int'
なんでこんな記事書いたの?
実は、最初はこんなコードを書いてました。
from enum import Enum
class Status(Enum):
NORMAL = 0
WARNING = 1
ERROR = 2
@classmethod
def from_int(cls, value):
for status in cls:
if day.value == value:
return status
raise ValueError("Invalid value")
status = Days.from_int(0)
print(status)
# Status.NORMAL
このfrom_intを定義した共通クラスを設けて、それを継承して…?
PythonのEnum使いにくくない!?とか思ってたんですが、以下のStackOverFlowの記事を見つけました。
コンストラクタにvalue渡したら変換してくれんのかーい!めちゃくちゃ便利やんけ!
公式ドキュメントのHOWTOにも書いてました。公式ドキュメントにちゃんと1回は目を通そうね!はい…
以上!