Python enums revisited

Luis P Caamano lcaamano at mindspring.com
Thu Oct 4 12:24:41 EDT 2001


Will Ware posted some enum code a while ago, which I started
playing with.  I'm now using a modified version (included
below) mainly for error numbers.  It's just very nice not to
worry about values.  Instead of:

class Error:
  onerror = 1
  anothererror = 2
  theother = 3
  bigone = 24
  baderror = 25

etc.

it's simply better to have

errors = """
onerror=1,
anothererror,
theother,
bigone = 24,
baderror,
"""
Error = enum(errors)

and let the enum class worry about the values.

The enum class simply creates a dictionary, just like the simple
class would've, but it automatically assigns the values.  The enum
class ends up parsing the string and creating copies of what it
needs.  I put the big error string and the call to enum in its
own file, and thus, the memory used by the big string ends up
going out of scope and freed at collection time.

Here's the code.

--
Luis P Caamano
Atlanta, GA, USA

====enum.py====
#
# enum.py
#
#	This file contains the enum class, which implements
#       C style enums for python
#

class EnumException(Exception): pass
class InvalidEnumVal(EnumException): pass
class InvalidEnum(EnumException): pass
class DuplicateEnum(EnumException): pass
class DuplicateEnumVal(EnumException): pass

class enum:
    def __init__(self, enumstr):
        self.lookup = { }
        self.reverseLookup = { }
        evalue = 0

        elist = enumstr.split(',')

        for e in elist:
            item = e.strip().split('=')

            ename = item[0].strip()
            if ename == '':
                continue

            if len(item) == 2:
                try:
                    evalue = int(item[1].strip(), 0)
                except ValueError:
                    raise InvalidEnumVal, 'Invalid value for: ' + ename
            elif len(item) != 1:
                raise InvalidEnum, "Invalid enum: " + e

            if self.lookup.has_key(ename):
                raise DuplicateEnum, "Duplicate enum name: " + ename
            if self.reverseLookup.has_key(evalue):
                raise DuplicateEnumVal,"Duplicate value %d for
%s"%(evalue,ename)

            self.lookup[ename] = evalue
            self.reverseLookup[evalue] = ename
            evalue = evalue + 1

    def __getattr__(self, attr):
        return self.lookup[attr]

    def __len__(self):
        return len(self.lookup)

    def __repr__(self):
        s = ''
        values = self.lookup.values()
        values.sort()
        for e in values:
            s = s + '%s = %d\n' % (self.reverseLookup[e], e)
        return s

def main():
    str = """
JETTA,
RABBIT,
BEETLE,
THING=400,
PASSAT,
GOLF,
CABRIO=700,
EUROVAN,
"""
    v = enum(str)
    print v
    print 'PASSAT = %d' % v.PASSAT

    e1 = enum('TEST,,TEST2')
    print 'e1 len = %d' % len(e1)
    print e1

    try:
        e2 = enum('TEST,TEST1=jjj')
    except InvalidEnumVal, msg:
        print 'Invalid Enum Value Passed'
        print '    %s' % msg
    else:
        print 'Invalid Enum Value Failed'

    try:
        e2 = enum('TEST,TEST1=76=87=KJK')
    except InvalidEnum, msg:
        print 'Invalid Enum Passed'
        print '    %s' % msg
    else:
        print 'Invalid Enum Failed'

    try:
        e2 = enum('TEST,TEST')
    except DuplicateEnum, msg:
        print 'Duplicate Enum Passed'
        print '    %s' % msg
    else:
        print 'Duplicate Enum Failed'

    try:
        e2 = enum('TEST,TEST1=0')
    except DuplicateEnumVal, msg:
        print 'Duplicate Enum Val Passed'
        print '    %s' % msg
    else:
        print 'Duplicate Enum Val Failed'

if __name__ == "__main__":
    main()



More information about the Python-list mailing list