| 1 | """Enumeration metaclass."""
|
|---|
| 2 |
|
|---|
| 3 | class EnumMetaclass(type):
|
|---|
| 4 | """Metaclass for enumeration.
|
|---|
| 5 |
|
|---|
| 6 | To define your own enumeration, do something like
|
|---|
| 7 |
|
|---|
| 8 | class Color(Enum):
|
|---|
| 9 | red = 1
|
|---|
| 10 | green = 2
|
|---|
| 11 | blue = 3
|
|---|
| 12 |
|
|---|
| 13 | Now, Color.red, Color.green and Color.blue behave totally
|
|---|
| 14 | different: they are enumerated values, not integers.
|
|---|
| 15 |
|
|---|
| 16 | Enumerations cannot be instantiated; however they can be
|
|---|
| 17 | subclassed.
|
|---|
| 18 | """
|
|---|
| 19 |
|
|---|
| 20 | def __init__(cls, name, bases, dict):
|
|---|
| 21 | super(EnumMetaclass, cls).__init__(name, bases, dict)
|
|---|
| 22 | cls._members = []
|
|---|
| 23 | for attr in dict.keys():
|
|---|
| 24 | if not (attr.startswith('__') and attr.endswith('__')):
|
|---|
| 25 | enumval = EnumInstance(name, attr, dict[attr])
|
|---|
| 26 | setattr(cls, attr, enumval)
|
|---|
| 27 | cls._members.append(attr)
|
|---|
| 28 |
|
|---|
| 29 | def __getattr__(cls, name):
|
|---|
| 30 | if name == "__members__":
|
|---|
| 31 | return cls._members
|
|---|
| 32 | raise AttributeError, name
|
|---|
| 33 |
|
|---|
| 34 | def __repr__(cls):
|
|---|
| 35 | s1 = s2 = ""
|
|---|
| 36 | enumbases = [base.__name__ for base in cls.__bases__
|
|---|
| 37 | if isinstance(base, EnumMetaclass) and not base is Enum]
|
|---|
| 38 | if enumbases:
|
|---|
| 39 | s1 = "(%s)" % ", ".join(enumbases)
|
|---|
| 40 | enumvalues = ["%s: %d" % (val, getattr(cls, val))
|
|---|
| 41 | for val in cls._members]
|
|---|
| 42 | if enumvalues:
|
|---|
| 43 | s2 = ": {%s}" % ", ".join(enumvalues)
|
|---|
| 44 | return "%s%s%s" % (cls.__name__, s1, s2)
|
|---|
| 45 |
|
|---|
| 46 | class FullEnumMetaclass(EnumMetaclass):
|
|---|
| 47 | """Metaclass for full enumerations.
|
|---|
| 48 |
|
|---|
| 49 | A full enumeration displays all the values defined in base classes.
|
|---|
| 50 | """
|
|---|
| 51 |
|
|---|
| 52 | def __init__(cls, name, bases, dict):
|
|---|
| 53 | super(FullEnumMetaclass, cls).__init__(name, bases, dict)
|
|---|
| 54 | for obj in cls.__mro__:
|
|---|
| 55 | if isinstance(obj, EnumMetaclass):
|
|---|
| 56 | for attr in obj._members:
|
|---|
| 57 | # XXX inefficient
|
|---|
| 58 | if not attr in cls._members:
|
|---|
| 59 | cls._members.append(attr)
|
|---|
| 60 |
|
|---|
| 61 | class EnumInstance(int):
|
|---|
| 62 | """Class to represent an enumeration value.
|
|---|
| 63 |
|
|---|
| 64 | EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
|
|---|
| 65 | like the integer 12 when compared, but doesn't support arithmetic.
|
|---|
| 66 |
|
|---|
| 67 | XXX Should it record the actual enumeration rather than just its
|
|---|
| 68 | name?
|
|---|
| 69 | """
|
|---|
| 70 |
|
|---|
| 71 | def __new__(cls, classname, enumname, value):
|
|---|
| 72 | return int.__new__(cls, value)
|
|---|
| 73 |
|
|---|
| 74 | def __init__(self, classname, enumname, value):
|
|---|
| 75 | self.__classname = classname
|
|---|
| 76 | self.__enumname = enumname
|
|---|
| 77 |
|
|---|
| 78 | def __repr__(self):
|
|---|
| 79 | return "EnumInstance(%s, %s, %d)" % (self.__classname, self.__enumname,
|
|---|
| 80 | self)
|
|---|
| 81 |
|
|---|
| 82 | def __str__(self):
|
|---|
| 83 | return "%s.%s" % (self.__classname, self.__enumname)
|
|---|
| 84 |
|
|---|
| 85 | class Enum:
|
|---|
| 86 | __metaclass__ = EnumMetaclass
|
|---|
| 87 |
|
|---|
| 88 | class FullEnum:
|
|---|
| 89 | __metaclass__ = FullEnumMetaclass
|
|---|
| 90 |
|
|---|
| 91 | def _test():
|
|---|
| 92 |
|
|---|
| 93 | class Color(Enum):
|
|---|
| 94 | red = 1
|
|---|
| 95 | green = 2
|
|---|
| 96 | blue = 3
|
|---|
| 97 |
|
|---|
| 98 | print Color.red
|
|---|
| 99 |
|
|---|
| 100 | print repr(Color.red)
|
|---|
| 101 | print Color.red == Color.red
|
|---|
| 102 | print Color.red == Color.blue
|
|---|
| 103 | print Color.red == 1
|
|---|
| 104 | print Color.red == 2
|
|---|
| 105 |
|
|---|
| 106 | class ExtendedColor(Color):
|
|---|
| 107 | white = 0
|
|---|
| 108 | orange = 4
|
|---|
| 109 | yellow = 5
|
|---|
| 110 | purple = 6
|
|---|
| 111 | black = 7
|
|---|
| 112 |
|
|---|
| 113 | print ExtendedColor.orange
|
|---|
| 114 | print ExtendedColor.red
|
|---|
| 115 |
|
|---|
| 116 | print Color.red == ExtendedColor.red
|
|---|
| 117 |
|
|---|
| 118 | class OtherColor(Enum):
|
|---|
| 119 | white = 4
|
|---|
| 120 | blue = 5
|
|---|
| 121 |
|
|---|
| 122 | class MergedColor(Color, OtherColor):
|
|---|
| 123 | pass
|
|---|
| 124 |
|
|---|
| 125 | print MergedColor.red
|
|---|
| 126 | print MergedColor.white
|
|---|
| 127 |
|
|---|
| 128 | print Color
|
|---|
| 129 | print ExtendedColor
|
|---|
| 130 | print OtherColor
|
|---|
| 131 | print MergedColor
|
|---|
| 132 |
|
|---|
| 133 | def _test2():
|
|---|
| 134 |
|
|---|
| 135 | class Color(FullEnum):
|
|---|
| 136 | red = 1
|
|---|
| 137 | green = 2
|
|---|
| 138 | blue = 3
|
|---|
| 139 |
|
|---|
| 140 | print Color.red
|
|---|
| 141 |
|
|---|
| 142 | print repr(Color.red)
|
|---|
| 143 | print Color.red == Color.red
|
|---|
| 144 | print Color.red == Color.blue
|
|---|
| 145 | print Color.red == 1
|
|---|
| 146 | print Color.red == 2
|
|---|
| 147 |
|
|---|
| 148 | class ExtendedColor(Color):
|
|---|
| 149 | white = 0
|
|---|
| 150 | orange = 4
|
|---|
| 151 | yellow = 5
|
|---|
| 152 | purple = 6
|
|---|
| 153 | black = 7
|
|---|
| 154 |
|
|---|
| 155 | print ExtendedColor.orange
|
|---|
| 156 | print ExtendedColor.red
|
|---|
| 157 |
|
|---|
| 158 | print Color.red == ExtendedColor.red
|
|---|
| 159 |
|
|---|
| 160 | class OtherColor(FullEnum):
|
|---|
| 161 | white = 4
|
|---|
| 162 | blue = 5
|
|---|
| 163 |
|
|---|
| 164 | class MergedColor(Color, OtherColor):
|
|---|
| 165 | pass
|
|---|
| 166 |
|
|---|
| 167 | print MergedColor.red
|
|---|
| 168 | print MergedColor.white
|
|---|
| 169 |
|
|---|
| 170 | print Color
|
|---|
| 171 | print ExtendedColor
|
|---|
| 172 | print OtherColor
|
|---|
| 173 | print MergedColor
|
|---|
| 174 |
|
|---|
| 175 | if __name__ == '__main__':
|
|---|
| 176 | _test()
|
|---|
| 177 | _test2()
|
|---|