chikuchikugonzalezの雑記帳

趣味とか日記とかメモとか(∩゚д゚)

PythonでEnum型

いっこ前のでメタクラスでシングルトンとかやりましたが、なんとなく必要になったEnum型の実装もメタクラスでやってみた。
いや先人の知恵でEnum型は実装済みだったんですが、Enumっぽいクラスのサブクラスにするのがなんとなくやだったので(;´∀`)
つまりはメタクラスで完結できないかってことでした

で結果。メタクラスで完結できます。
要はEnumの値となる名前のクラスを定義して、それのインスタンスで元クラスのフィールドを置き換えてやればいい。*1

class EnumType(type):
	def __init__(cls, name, bases, dic):
		super(EnumType, cls).__init__(name, bases, dic)

		reprFunc = lambda self: "<class %s, value=%s>" % (self.__class__.__name__, self.value)
		strFunc = lambda self: "%d" % self.value
		def newFunc(cls, *args, **kwargs):
			"""新規インスタンス生成を阻止します"""
			raise RuntimeError("Create another instance of EnumType is not allowed")
		for key, value in dic.items():
			if not key.startswith('_'):
				clsType = type("%s.%s" % (cls.__name__, key), (cls,), {})
				item = clsType()
				setattr(cls, key, item)
				setattr(item, 'value', value)
				setattr(item, 'name', key)
				setattr(clsType, '__repr__', reprFunc)
				setattr(clsType, '__str__', strFunc)
				setattr(clsType, '__new__', newFunc)

使い方:

class Key(metaclass=EnumType):
    A = 0
    B = 1
    C = 2

print(Key.A)
print(Key.B)
print(Key.C)
print(repr(Key.A))
print(repr(Key.B))
print(repr(Key.C))

作ったはいいが役に立つのかコレ

*1:コンストラクタが連続起動している気がしますが無視します