mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Enumeration metaclass.
 | 
						|
 | 
						|
XXX This is very much a work in progress.
 | 
						|
 | 
						|
"""
 | 
						|
 | 
						|
import string
 | 
						|
 | 
						|
class EnumMetaClass:
 | 
						|
    """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__(self, name, bases, dict):
 | 
						|
	"""Constructor -- create an enumeration.
 | 
						|
 | 
						|
	Called at the end of the class statement.  The arguments are
 | 
						|
	the name of the new class, a tuple containing the base
 | 
						|
	classes, and a dictionary containing everything that was
 | 
						|
	entered in the class' namespace during execution of the class
 | 
						|
	statement.  In the above example, it would be {'red': 1,
 | 
						|
	'green': 2, 'blue': 3}.
 | 
						|
 | 
						|
	"""
 | 
						|
	for base in bases:
 | 
						|
	    if base.__class__ is not EnumMetaClass:
 | 
						|
		raise TypeError, "Enumeration base class must be enumeration"
 | 
						|
	bases = filter(lambda x: x is not Enum, bases)
 | 
						|
	self.__name__ = name
 | 
						|
	self.__bases__ = bases
 | 
						|
	self.__dict = {}
 | 
						|
	for key, value in dict.items():
 | 
						|
	    self.__dict[key] = EnumInstance(name, key, value)
 | 
						|
 | 
						|
    def __getattr__(self, name):
 | 
						|
	"""Return an enumeration value.
 | 
						|
 | 
						|
	For example, Color.red returns the value corresponding to red.
 | 
						|
 | 
						|
	XXX Perhaps the values should be created in the constructor?
 | 
						|
 | 
						|
	This looks in the class dictionary and if it is not found
 | 
						|
	there asks the base classes.
 | 
						|
 | 
						|
	The special attribute __members__ returns the list of names
 | 
						|
	defined in this class (it does not merge in the names defined
 | 
						|
	in base classes).
 | 
						|
 | 
						|
	"""
 | 
						|
	if name == '__members__':
 | 
						|
	    return self.__dict.keys()
 | 
						|
 | 
						|
	try:
 | 
						|
	    return self.__dict[name]
 | 
						|
	except KeyError:
 | 
						|
	    for base in self.__bases__:
 | 
						|
		try:
 | 
						|
		    return getattr(base, name)
 | 
						|
		except AttributeError:
 | 
						|
		    continue
 | 
						|
 | 
						|
	raise AttributeError, name
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
	s = self.__name__
 | 
						|
	if self.__bases__:
 | 
						|
	    s = s + '(' + string.join(map(lambda x: x.__name__,
 | 
						|
					  self.__bases__), ", ") + ')'
 | 
						|
	if self.__dict:
 | 
						|
	    list = []
 | 
						|
	    for key, value in self.__dict.items():
 | 
						|
		list.append("%s: %s" % (key, int(value)))
 | 
						|
	    s = "%s: {%s}" % (s, string.join(list, ", "))
 | 
						|
	return s
 | 
						|
 | 
						|
 | 
						|
class EnumInstance:
 | 
						|
    """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 __init__(self, classname, enumname, value):
 | 
						|
	self.__classname = classname
 | 
						|
	self.__enumname = enumname
 | 
						|
	self.__value = value
 | 
						|
 | 
						|
    def __int__(self):
 | 
						|
	return self.__value
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
	return "EnumInstance(%s, %s, %s)" % (`self.__classname`,
 | 
						|
					     `self.__enumname`,
 | 
						|
					     `self.__value`)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
	return "%s.%s" % (self.__classname, self.__enumname)
 | 
						|
 | 
						|
    def __cmp__(self, other):
 | 
						|
	return cmp(self.__value, int(other))
 | 
						|
 | 
						|
 | 
						|
# Create the base class for enumerations.
 | 
						|
# It is an empty enumeration.
 | 
						|
Enum = EnumMetaClass("Enum", (), {})
 | 
						|
 | 
						|
 | 
						|
def _test():
 | 
						|
 | 
						|
    class Color(Enum):
 | 
						|
	red = 1
 | 
						|
	green = 2
 | 
						|
	blue = 3
 | 
						|
 | 
						|
    print Color.red
 | 
						|
    print dir(Color)
 | 
						|
 | 
						|
    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
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    _test()
 |