home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / metaclasses / Enum.py < prev    next >
Text File  |  1997-08-25  |  4KB  |  170 lines

  1. """Enumeration metaclass.
  2.  
  3. XXX This is very much a work in progress.
  4.  
  5. """
  6.  
  7. import string
  8.  
  9. class EnumMetaClass:
  10.     """Metaclass for enumeration.
  11.  
  12.     To define your own enumeration, do something like
  13.  
  14.     class Color(Enum):
  15.     red = 1
  16.     green = 2
  17.     blue = 3
  18.  
  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):
  28.     """Constructor -- create an enumeration.
  29.  
  30.     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}.
  36.  
  37.     """
  38.     for base in bases:
  39.         if base.__class__ is not EnumMetaClass:
  40.         raise TypeError, "Enumeration base class must be enumeration"
  41.     bases = filter(lambda x: x is not Enum, bases)
  42.     self.__name__ = name
  43.     self.__bases__ = bases
  44.     self.__dict = {}
  45.     for key, value in dict.items():
  46.         self.__dict[key] = EnumInstance(name, key, value)
  47.  
  48.     def __getattr__(self, name):
  49.     """Return an enumeration value.
  50.  
  51.     For example, Color.red returns the value corresponding to red.
  52.  
  53.     XXX Perhaps the values should be created in the constructor?
  54.  
  55.     This looks in the class dictionary and if it is not found
  56.     there asks the base classes.
  57.  
  58.     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).
  61.  
  62.     """
  63.     if name == '__members__':
  64.         return self.__dict.keys()
  65.  
  66.     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
  74.  
  75.     raise AttributeError, name
  76.  
  77.     def __repr__(self):
  78.     s = self.__name__
  79.     if self.__bases__:
  80.         s = s + '(' + string.join(map(lambda x: x.__name__,
  81.                       self.__bases__), ", ") + ')'
  82.     if self.__dict:
  83.         list = []
  84.         for key, value in self.__dict.items():
  85.         list.append("%s: %s" % (key, int(value)))
  86.         s = "%s: {%s}" % (s, string.join(list, ", "))
  87.     return s
  88.  
  89.  
  90. class EnumInstance:
  91.     """Class to represent an enumeration value.
  92.  
  93.     EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
  94.     like the integer 12 when compared, but doesn't support arithmetic.
  95.  
  96.     XXX Should it record the actual enumeration rather than just its
  97.     name?
  98.  
  99.     """
  100.  
  101.     def __init__(self, classname, enumname, value):
  102.     self.__classname = classname
  103.     self.__enumname = enumname
  104.     self.__value = value
  105.  
  106.     def __int__(self):
  107.     return self.__value
  108.  
  109.     def __repr__(self):
  110.     return "EnumInstance(%s, %s, %s)" % (`self.__classname`,
  111.                          `self.__enumname`,
  112.                          `self.__value`)
  113.  
  114.     def __str__(self):
  115.     return "%s.%s" % (self.__classname, self.__enumname)
  116.  
  117.     def __cmp__(self, other):
  118.     return cmp(self.__value, int(other))
  119.  
  120.  
  121. # Create the base class for enumerations.
  122. # It is an empty enumeration.
  123. Enum = EnumMetaClass("Enum", (), {})
  124.  
  125.  
  126. def _test():
  127.  
  128.     class Color(Enum):
  129.     red = 1
  130.     green = 2
  131.     blue = 3
  132.  
  133.     print Color.red
  134.     print dir(Color)
  135.  
  136.     print Color.red == Color.red
  137.     print Color.red == Color.blue
  138.     print Color.red == 1
  139.     print Color.red == 2
  140.  
  141.     class ExtendedColor(Color):
  142.     white = 0
  143.     orange = 4
  144.     yellow = 5
  145.     purple = 6
  146.     black = 7
  147.  
  148.     print ExtendedColor.orange
  149.     print ExtendedColor.red
  150.  
  151.     print Color.red == ExtendedColor.red
  152.  
  153.     class OtherColor(Enum):
  154.     white = 4
  155.     blue = 5
  156.  
  157.     class MergedColor(Color, OtherColor):
  158.     pass
  159.  
  160.     print MergedColor.red
  161.     print MergedColor.white
  162.  
  163.     print Color
  164.     print ExtendedColor
  165.     print OtherColor
  166.     print MergedColor
  167.  
  168. if __name__ == '__main__':
  169.     _test()
  170.