#!/usr/bin/env python def enum(*sequential, **named): # Check for duplicate keys names = list(sequential) names.extend(named.keys()) if len(set(names)) != len(names): raise KeyError('Cannot create enumeration with duplicate keys!') # Build property dict enums = dict(zip(sequential, range(len(sequential))), **named) if not enums: raise KeyError('Cannot create empty enumeration') if len(set(enums.values())) < len(enums): raise ValueError('Cannot create enumeration with duplicate values!') # Function to be called as fset/fdel def err_func(*args, **kwargs): raise AttributeError('Enumeration is immutable!') # function to be called as fget def getter(cls, val): return lambda cls: val # Create a base type t = type('enum', (object,), {}) # Add properties to class by duck-punching for attr, val in enums.iteritems(): setattr(t, attr, property(getter(t, val), err_func, err_func)) # Return an instance of the new class return t() if __name__ == "__main__": """A small ammount of code to demo the functionality""" try: print 'Creating empty enum...', e = enum() print 'OK!' except KeyError as e: print 'ERROR:', e try: print 'Creating enum with duplicate keys...', e = enum('OK', 'OK', OK=2) print 'OK!' except KeyError as e: print 'ERROR:', e try: print 'Creating enum with duplicate values...', e = enum(OK=1, PASS=1) print 'OK!' except ValueError as e: print 'ERROR:', e try: print 'Creating valid enum...', e = enum('OK', 'CANCEL', 'QUIT', test=4, ok='YES') print 'OK!' except Exception as e: print 'ERROR:', e # Immutable? try: print 'Changing e.OK = "ASDF"...', e.OK = 'ASDF' print 'OK!' except AttributeError as ex: print 'ERROR:', ex try: print 'Deleting e.OK...', del e.OK print 'OK!' except AttributeError as ex: print 'ERROR:', ex print e print e.OK print e.CANCEL print e.QUIT print e.test print e.ok