blob: eb52d79cee2e29711b52fdf2ec7730e6d470a929 [file] [log] [blame]
Guido van Rossum27e4aa31997-08-25 15:37:59 +00001"""Enumeration metaclass.
2
3XXX This is very much a work in progress.
4
5"""
Guido van Rossumbff110f1997-08-23 21:14:37 +00006
7import string
8
9class EnumMetaClass:
10 """Metaclass for enumeration.
11
12 To define your own enumeration, do something like
13
14 class Color(Enum):
Guido van Rossum4117e541998-09-14 16:44:15 +000015 red = 1
16 green = 2
17 blue = 3
Guido van Rossumbff110f1997-08-23 21:14:37 +000018
19 Now, Color.red, Color.green and Color.blue behave totally
20 different: they are enumerated values, not integers.
21
22 Enumerations cannot be instantiated; however they can be
23 subclassed.
24
25 """
26
27 def __init__(self, name, bases, dict):
Guido van Rossum4117e541998-09-14 16:44:15 +000028 """Constructor -- create an enumeration.
Guido van Rossumbff110f1997-08-23 21:14:37 +000029
Guido van Rossum4117e541998-09-14 16:44:15 +000030 Called at the end of the class statement. The arguments are
31 the name of the new class, a tuple containing the base
32 classes, and a dictionary containing everything that was
33 entered in the class' namespace during execution of the class
34 statement. In the above example, it would be {'red': 1,
35 'green': 2, 'blue': 3}.
Guido van Rossumbff110f1997-08-23 21:14:37 +000036
Guido van Rossum4117e541998-09-14 16:44:15 +000037 """
38 for base in bases:
39 if base.__class__ is not EnumMetaClass:
Collin Winter6f2df4d2007-07-17 20:59:35 +000040 raise TypeError("Enumeration base class must be enumeration")
41 bases = [x for x in bases if x is not Enum]
Guido van Rossum4117e541998-09-14 16:44:15 +000042 self.__name__ = name
43 self.__bases__ = bases
44 self.__dict = {}
Skip Montanaro1e8ce582007-08-06 21:07:53 +000045 for key, value in dict.items():
Guido van Rossum4117e541998-09-14 16:44:15 +000046 self.__dict[key] = EnumInstance(name, key, value)
Guido van Rossumbff110f1997-08-23 21:14:37 +000047
48 def __getattr__(self, name):
Guido van Rossum4117e541998-09-14 16:44:15 +000049 """Return an enumeration value.
Guido van Rossumbff110f1997-08-23 21:14:37 +000050
Guido van Rossum4117e541998-09-14 16:44:15 +000051 For example, Color.red returns the value corresponding to red.
Guido van Rossumbff110f1997-08-23 21:14:37 +000052
Guido van Rossum4117e541998-09-14 16:44:15 +000053 XXX Perhaps the values should be created in the constructor?
Guido van Rossumbff110f1997-08-23 21:14:37 +000054
Guido van Rossum4117e541998-09-14 16:44:15 +000055 This looks in the class dictionary and if it is not found
56 there asks the base classes.
Guido van Rossumbff110f1997-08-23 21:14:37 +000057
Guido van Rossum4117e541998-09-14 16:44:15 +000058 The special attribute __members__ returns the list of names
59 defined in this class (it does not merge in the names defined
60 in base classes).
Guido van Rossumbff110f1997-08-23 21:14:37 +000061
Guido van Rossum4117e541998-09-14 16:44:15 +000062 """
63 if name == '__members__':
Collin Winter6f2df4d2007-07-17 20:59:35 +000064 return list(self.__dict.keys())
Guido van Rossumbff110f1997-08-23 21:14:37 +000065
Guido van Rossum4117e541998-09-14 16:44:15 +000066 try:
67 return self.__dict[name]
68 except KeyError:
69 for base in self.__bases__:
70 try:
71 return getattr(base, name)
72 except AttributeError:
73 continue
Guido van Rossumbff110f1997-08-23 21:14:37 +000074
Collin Winter6f2df4d2007-07-17 20:59:35 +000075 raise AttributeError(name)
Guido van Rossumbff110f1997-08-23 21:14:37 +000076
77 def __repr__(self):
Guido van Rossum4117e541998-09-14 16:44:15 +000078 s = self.__name__
79 if self.__bases__:
Collin Winter6f2df4d2007-07-17 20:59:35 +000080 s = s + '(' + string.join([x.__name__ for x in self.__bases__], ", ") + ')'
Guido van Rossum4117e541998-09-14 16:44:15 +000081 if self.__dict:
82 list = []
Skip Montanaro1e8ce582007-08-06 21:07:53 +000083 for key, value in self.__dict.items():
Guido van Rossum4117e541998-09-14 16:44:15 +000084 list.append("%s: %s" % (key, int(value)))
85 s = "%s: {%s}" % (s, string.join(list, ", "))
86 return s
Guido van Rossumbff110f1997-08-23 21:14:37 +000087
88
89class EnumInstance:
90 """Class to represent an enumeration value.
91
92 EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
93 like the integer 12 when compared, but doesn't support arithmetic.
94
95 XXX Should it record the actual enumeration rather than just its
96 name?
97
98 """
99
100 def __init__(self, classname, enumname, value):
Guido van Rossum4117e541998-09-14 16:44:15 +0000101 self.__classname = classname
102 self.__enumname = enumname
103 self.__value = value
Guido van Rossumbff110f1997-08-23 21:14:37 +0000104
105 def __int__(self):
Guido van Rossum4117e541998-09-14 16:44:15 +0000106 return self.__value
Guido van Rossumbff110f1997-08-23 21:14:37 +0000107
108 def __repr__(self):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000109 return "EnumInstance(%r, %r, %r)" % (self.__classname,
110 self.__enumname,
111 self.__value)
Guido van Rossumbff110f1997-08-23 21:14:37 +0000112
113 def __str__(self):
Guido van Rossum4117e541998-09-14 16:44:15 +0000114 return "%s.%s" % (self.__classname, self.__enumname)
Guido van Rossumbff110f1997-08-23 21:14:37 +0000115
116 def __cmp__(self, other):
Guido van Rossum4117e541998-09-14 16:44:15 +0000117 return cmp(self.__value, int(other))
Guido van Rossumbff110f1997-08-23 21:14:37 +0000118
119
120# Create the base class for enumerations.
121# It is an empty enumeration.
122Enum = EnumMetaClass("Enum", (), {})
123
124
125def _test():
126
127 class Color(Enum):
Guido van Rossum4117e541998-09-14 16:44:15 +0000128 red = 1
129 green = 2
130 blue = 3
Guido van Rossumbff110f1997-08-23 21:14:37 +0000131
Collin Winter6f2df4d2007-07-17 20:59:35 +0000132 print(Color.red)
133 print(dir(Color))
Guido van Rossumbff110f1997-08-23 21:14:37 +0000134
Collin Winter6f2df4d2007-07-17 20:59:35 +0000135 print(Color.red == Color.red)
136 print(Color.red == Color.blue)
137 print(Color.red == 1)
138 print(Color.red == 2)
Guido van Rossumbff110f1997-08-23 21:14:37 +0000139
140 class ExtendedColor(Color):
Guido van Rossum4117e541998-09-14 16:44:15 +0000141 white = 0
142 orange = 4
143 yellow = 5
144 purple = 6
145 black = 7
Guido van Rossumbff110f1997-08-23 21:14:37 +0000146
Collin Winter6f2df4d2007-07-17 20:59:35 +0000147 print(ExtendedColor.orange)
148 print(ExtendedColor.red)
Guido van Rossumbff110f1997-08-23 21:14:37 +0000149
Collin Winter6f2df4d2007-07-17 20:59:35 +0000150 print(Color.red == ExtendedColor.red)
Guido van Rossumbff110f1997-08-23 21:14:37 +0000151
152 class OtherColor(Enum):
Guido van Rossum4117e541998-09-14 16:44:15 +0000153 white = 4
154 blue = 5
Guido van Rossumbff110f1997-08-23 21:14:37 +0000155
156 class MergedColor(Color, OtherColor):
Guido van Rossum4117e541998-09-14 16:44:15 +0000157 pass
Guido van Rossumbff110f1997-08-23 21:14:37 +0000158
Collin Winter6f2df4d2007-07-17 20:59:35 +0000159 print(MergedColor.red)
160 print(MergedColor.white)
Guido van Rossumbff110f1997-08-23 21:14:37 +0000161
Collin Winter6f2df4d2007-07-17 20:59:35 +0000162 print(Color)
163 print(ExtendedColor)
164 print(OtherColor)
165 print(MergedColor)
Guido van Rossumbff110f1997-08-23 21:14:37 +0000166
167if __name__ == '__main__':
168 _test()