127e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum"""Enumeration metaclass. 227e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum 327e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van RossumXXX This is very much a work in progress. 427e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum 527e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum""" 6bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 7bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumimport string 8bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 9bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumclass EnumMetaClass: 10bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum """Metaclass for enumeration. 11bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 12bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum To define your own enumeration, do something like 13bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 14bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum class Color(Enum): 154117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum red = 1 164117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum green = 2 174117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum blue = 3 18bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 19bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum Now, Color.red, Color.green and Color.blue behave totally 20bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum different: they are enumerated values, not integers. 21bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 22bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum Enumerations cannot be instantiated; however they can be 23bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum subclassed. 24bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 25bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum """ 26bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 27bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __init__(self, name, bases, dict): 284117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum """Constructor -- create an enumeration. 294117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum 304117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum Called at the end of the class statement. The arguments are 314117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum the name of the new class, a tuple containing the base 324117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum classes, and a dictionary containing everything that was 334117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum entered in the class' namespace during execution of the class 344117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum statement. In the above example, it would be {'red': 1, 354117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum 'green': 2, 'blue': 3}. 364117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum 374117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum """ 384117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum for base in bases: 394117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum if base.__class__ is not EnumMetaClass: 404117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum raise TypeError, "Enumeration base class must be enumeration" 414117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum bases = filter(lambda x: x is not Enum, bases) 424117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__name__ = name 434117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__bases__ = bases 444117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__dict = {} 454117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum for key, value in dict.items(): 464117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__dict[key] = EnumInstance(name, key, value) 47bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 48bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __getattr__(self, name): 494117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum """Return an enumeration value. 50bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 514117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum For example, Color.red returns the value corresponding to red. 52bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 534117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum XXX Perhaps the values should be created in the constructor? 54bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 554117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum This looks in the class dictionary and if it is not found 564117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum there asks the base classes. 57bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 584117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum The special attribute __members__ returns the list of names 594117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum defined in this class (it does not merge in the names defined 604117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum in base classes). 61bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 624117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum """ 634117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum if name == '__members__': 644117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum return self.__dict.keys() 65bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 664117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum try: 674117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum return self.__dict[name] 684117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum except KeyError: 694117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum for base in self.__bases__: 704117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum try: 714117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum return getattr(base, name) 724117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum except AttributeError: 734117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum continue 74bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 754117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum raise AttributeError, name 76bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 77bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __repr__(self): 784117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum s = self.__name__ 794117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum if self.__bases__: 804117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum s = s + '(' + string.join(map(lambda x: x.__name__, 814117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__bases__), ", ") + ')' 824117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum if self.__dict: 834117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum list = [] 844117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum for key, value in self.__dict.items(): 854117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum list.append("%s: %s" % (key, int(value))) 864117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum s = "%s: {%s}" % (s, string.join(list, ", ")) 874117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum return s 88bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 89bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 90bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumclass EnumInstance: 91bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum """Class to represent an enumeration value. 92bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 93bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves 94bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum like the integer 12 when compared, but doesn't support arithmetic. 95bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 96bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum XXX Should it record the actual enumeration rather than just its 97bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum name? 98bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 99bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum """ 100bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 101bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __init__(self, classname, enumname, value): 1024117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__classname = classname 1034117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__enumname = enumname 1044117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum self.__value = value 105bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 106bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __int__(self): 1074117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum return self.__value 108bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 109bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __repr__(self): 11070a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald return "EnumInstance(%r, %r, %r)" % (self.__classname, 11170a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald self.__enumname, 11270a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald self.__value) 113bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 114bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __str__(self): 1154117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum return "%s.%s" % (self.__classname, self.__enumname) 116bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 117bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum def __cmp__(self, other): 1184117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum return cmp(self.__value, int(other)) 119bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 120bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 121bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum# Create the base class for enumerations. 122bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum# It is an empty enumeration. 123bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van RossumEnum = EnumMetaClass("Enum", (), {}) 124bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 125bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 126bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumdef _test(): 127bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 128bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum class Color(Enum): 1294117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum red = 1 1304117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum green = 2 1314117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum blue = 3 132bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 133bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print Color.red 134bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print dir(Color) 135bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 136bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print Color.red == Color.red 137bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print Color.red == Color.blue 138bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print Color.red == 1 139bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print Color.red == 2 140bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 141bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum class ExtendedColor(Color): 1424117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum white = 0 1434117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum orange = 4 1444117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum yellow = 5 1454117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum purple = 6 1464117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum black = 7 147bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 148bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print ExtendedColor.orange 149bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print ExtendedColor.red 150bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 151bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print Color.red == ExtendedColor.red 152bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 153bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum class OtherColor(Enum): 1544117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum white = 4 1554117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum blue = 5 156bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 157bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum class MergedColor(Color, OtherColor): 1584117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum pass 159bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 160bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print MergedColor.red 161bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print MergedColor.white 162bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 163bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print Color 164bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print ExtendedColor 165bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print OtherColor 166bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum print MergedColor 167bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum 168bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumif __name__ == '__main__': 169bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum _test() 170