def Enum(*names):
    """See immutable symbolic enumeration types by Zoran Isailovski
    (see http://code.activestate.com/recipes/413486-first-class-enums-in-python/)

    - Enums are immutable; attributes cannot be added, deleted or changed.
    - Enums are iterable.
    - Enum value access is symbolic and qualified, ex. Days.Monday (like in C#).
    - Enum values are true constants.
    - Enum values are comparable.
    - Enum values are invertible (useful for 2-valued enums, like Enum('no', 'yes').
    - Enum values are usable as truth values (in a C tradition, but this is debatable).
    - Enum values are reasonably introspective (by publishing their enum type and numeric value)

    Changed slightly to add '__doc__' tags to the generated
    enumeration types.  So to the above author's comments we add:

    - Enums and Enum values are documented.
    - enumeration values are type-checked during comparisons.
    """
    assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!

    class EnumClass(object):
        __slots__ = names
        def __contains__(self, v): return v in constants
        def __getitem__(self, i):  return constants[i]
        def __iter__(self):        return iter(constants)
        def __len__(self):         return len(constants)
        def __repr__(self):        return 'Enum' + str(names)
        def __str__(self):         return 'enum ' + str(constants)

    class EnumValue(object):
        __slots__ = ('__value')
        def __init__(self, value): self.__value = value
        value = property(lambda self: self.__value)
        type = property(lambda self: EnumType)
        def __hash__(self):        return hash(self.__value)
        def __cmp__(self, other):
            try:
                if self.type is other.type:
                    return cmp(self.__value, other.__value)
                else:
                    raise TypeError, "requires a '%s' object but received a '%s'" % ( self.type.__class__.__name__, other.type.__class__.__name__ )
            except AttributeError:
                raise TypeError, "requires a '%s' object but received a '%s'" % ( self.type.__class__.__name__, other.__class__.__name__ )
        def __invert__(self):      return constants[maximum - self.__value]
        def __nonzero__(self):     return bool(self.__value)
        def __repr__(self):        return str(names[self.__value])
        
    maximum = len(names) - 1
    constants = [None] * len(names)
    for i, each in enumerate(names):
        val = type(EnumValue)(
            'EnumValue', (EnumValue,), { '__doc__': 'Enumeration value "%s"' % each }
        )(i)
        setattr(EnumClass, each, val)
        constants[i] = val
    constants = tuple(constants)
    EnumType = type(EnumClass)(
        'EnumClass', (EnumClass,), { '__doc__': 'Enumeration of %s' % repr(constants) }
    )()
    return EnumType
See immutable symbolic enumeration types by Zoran Isailovski
    (see http://code.activestate.com/recipes/413486-first-class-enums-in-python/)

    - Enums are immutable; attributes cannot be added, deleted or changed.
    - Enums are iterable.
    - Enum value access is symbolic and qualified, ex. Days.Monday (like in C#).
    - Enum values are true constants.
    - Enum values are comparable.
    - Enum values are invertible (useful for 2-valued enums, like Enum('no', 'yes').
    - Enum values are usable as truth values (in a C tradition, but this is debatable).
    - Enum values are reasonably introspective (by publishing their enum type and numeric value)

    Changed slightly to add '__doc__' tags to the generated
    enumeration types.  So to the above author's comments we add:

    - Enums and Enum values are documented.
    - enumeration values are type-checked during comparisons.
    
recipes/Python/577482_Easy_property/recipe-577482.py