summaryrefslogtreecommitdiffstats
path: root/Demo/newmetaclasses/Enum.py
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2002-07-11 21:08:06 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2002-07-11 21:08:06 (GMT)
commita00331636bb8361f8c11ea9f279781fb6cc98e15 (patch)
tree0beacdccf2a9e11c84ebee1d5229ddfe48cd4903 /Demo/newmetaclasses/Enum.py
parent20e5abc86ec641286e3958799333966febdf1b63 (diff)
downloadcpython-a00331636bb8361f8c11ea9f279781fb6cc98e15.zip
cpython-a00331636bb8361f8c11ea9f279781fb6cc98e15.tar.gz
cpython-a00331636bb8361f8c11ea9f279781fb6cc98e15.tar.bz2
Add Enum and Eiffel examples using new-style classes.
Diffstat (limited to 'Demo/newmetaclasses/Enum.py')
-rw-r--r--Demo/newmetaclasses/Enum.py178
1 files changed, 178 insertions, 0 deletions
diff --git a/Demo/newmetaclasses/Enum.py b/Demo/newmetaclasses/Enum.py
new file mode 100644
index 0000000..8a00b59
--- /dev/null
+++ b/Demo/newmetaclasses/Enum.py
@@ -0,0 +1,178 @@
+"""Enumeration metaclass."""
+
+class EnumMetaclass(type):
+ """Metaclass for enumeration.
+
+ To define your own enumeration, do something like
+
+ class Color(Enum):
+ red = 1
+ green = 2
+ blue = 3
+
+ Now, Color.red, Color.green and Color.blue behave totally
+ different: they are enumerated values, not integers.
+
+ Enumerations cannot be instantiated; however they can be
+ subclassed.
+ """
+
+ def __init__(cls, name, bases, dict):
+ super(EnumMetaclass, cls).__init__(name, bases, dict)
+ cls._members = []
+ for attr in dict.keys():
+ if not (attr.startswith('__') and attr.endswith('__')):
+ enumval = EnumInstance(name, attr, dict[attr])
+ setattr(cls, attr, enumval)
+ cls._members.append(attr)
+
+ def __getattr__(cls, name):
+ if name == "__members__":
+ return cls._members
+ raise AttributeError, name
+
+ def __repr__(cls):
+ s1 = s2 = ""
+ enumbases = [base.__name__ for base in cls.__bases__
+ if isinstance(base, EnumMetaclass) and not base is Enum]
+ if enumbases:
+ s1 = "(%s)" % ", ".join(enumbases)
+ enumvalues = ["%s: %d" % (val, getattr(cls, val))
+ for val in cls._members]
+ if enumvalues:
+ s2 = ": {%s}" % ", ".join(enumvalues)
+ return "%s%s%s" % (cls.__name__, s1, s2)
+
+class FullEnumMetaclass(EnumMetaclass):
+ """Metaclass for full enumerations.
+
+ A full enumeration displays all the values defined in base classes.
+ """
+
+ def __init__(cls, name, bases, dict):
+ super(FullEnumMetaclass, cls).__init__(name, bases, dict)
+ for obj in cls.__mro__:
+ if isinstance(obj, EnumMetaclass):
+ for attr in obj._members:
+ # XXX inefficient
+ if not attr in cls._members:
+ cls._members.append(attr)
+
+class EnumInstance(int):
+ """Class to represent an enumeration value.
+
+ EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
+ like the integer 12 when compared, but doesn't support arithmetic.
+
+ XXX Should it record the actual enumeration rather than just its
+ name?
+ """
+
+ def __new__(cls, classname, enumname, value):
+ return int.__new__(cls, value)
+
+ def __init__(self, classname, enumname, value):
+ self.__classname = classname
+ self.__enumname = enumname
+
+ def __repr__(self):
+ return "EnumInstance(%s, %s, %d)" % (self.__classname, self.__enumname,
+ self)
+
+ def __str__(self):
+ return "%s.%s" % (self.__classname, self.__enumname)
+
+class Enum:
+ __metaclass__ = EnumMetaclass
+
+class FullEnum:
+ __metaclass__ = FullEnumMetaclass
+
+def _test():
+
+ class Color(Enum):
+ red = 1
+ green = 2
+ blue = 3
+
+ print Color.red
+
+ print `Color.red`
+ print Color.red == Color.red
+ print Color.red == Color.blue
+ print Color.red == 1
+ print Color.red == 2
+
+ class ExtendedColor(Color):
+ white = 0
+ orange = 4
+ yellow = 5
+ purple = 6
+ black = 7
+
+ print ExtendedColor.orange
+ print ExtendedColor.red
+
+ print Color.red == ExtendedColor.red
+
+ class OtherColor(Enum):
+ white = 4
+ blue = 5
+
+ class MergedColor(Color, OtherColor):
+ pass
+
+ print MergedColor.red
+ print MergedColor.white
+
+ print Color
+ print ExtendedColor
+ print OtherColor
+ print MergedColor
+
+def _test2():
+
+ class Color(FullEnum):
+ red = 1
+ green = 2
+ blue = 3
+
+ print Color.red
+
+ print `Color.red`
+ print Color.red == Color.red
+ print Color.red == Color.blue
+ print Color.red == 1
+ print Color.red == 2
+
+ class ExtendedColor(Color):
+ white = 0
+ orange = 4
+ yellow = 5
+ purple = 6
+ black = 7
+
+ print ExtendedColor.orange
+ print ExtendedColor.red
+
+ print Color.red == ExtendedColor.red
+
+ class OtherColor(FullEnum):
+ white = 4
+ blue = 5
+
+ class MergedColor(Color, OtherColor):
+ pass
+
+ print MergedColor.red
+ print MergedColor.white
+
+ print Color
+ print ExtendedColor
+ print OtherColor
+ print MergedColor
+
+if __name__ == '__main__':
+ _test()
+ _test2()
+