Enum

Pythonで列挙体を生成するユーティリティ関数作ってみた。
コンパイル時に型チェックしない言語/環境では、
その恩恵を受けられないため軽視されがちだけど。

値の生成だけでも欲しくなった。ここでは名前のリストを渡して、
値が適当に重複しない値になっていれば充分。程度の需要なので。
# 動機)wxPythonで リソースID を列挙するのが面倒だった。

 from __future__ import nested_scopes # for python2.1
 from types import ListType

 def enum_factory(func, enum, start):
   if type(enum) is not ListType:
     raise TypeError
   else:
     map(func, enum, range(start, start+len(enum))) 
 
 def import_enum_with_prefix(package, prefix, enum, start=0):
   import_enum(package, map(lambda s:prefix+s, enum), start)

 def import_enum(package, enum, start=0):
   def set_enum(k, v): package[k] = v
   enum_factory(set_enum, enum, start)

 def create_enum_class(enum, start=0):
   class _Enum_Class: pass
   enum_factory(lambda k,v:setattr(_Enum_Class,k,v), enum, start)
   return _Enum_Class

 def create_enum_object(enum, start=0):
   return create_enum_class(enum, start)()


 if __name__ == '__main__':
     enum = ["NAME", "TREE"]
     import_enum_with_prefix(locals(), "ID_", enum, 1)
     print ID_MENU
     print ID_TREE

     obj = create_enum_object(enum, 1)
     print obj.MENU
     print obj.TREE

     class EnumClass(create_enum_class(enum, 1)):
       def menu(self): print self.MENU
       def tree(self): print self.TREE

     obj = EnumClass()
     obj.menu()
     obj.tree()
     

考察:

  • ID_MENU_FOO_BAR と、globals()もしくはlocals() に読み込んでしまうと、名前空間の汚染が心配。prefix付けてれば安全だけど、でもdir() したときにエントリがたくさん表れてしまうのは読みにくい。
  • 辞書を作る。ID["MENU_FOO_BAR"] は、打つのが面倒。[" "]
  • クラスに閉じ込める。ID.MENU_FOO_BARと表記。