Will Ware posted some enum code [ http://groups.google.com/groups?hl=en&newwindow=1&selm=GIJJzq.Jx1%40world.std.com ] a while ago, which I started playing with. I am now using a modified version mainly for error numbers instead of an Error class. It's just very nice not to worry about values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | #
# 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 += 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()
|
It seems common to use a class to store the mapping between error names and error values. However, it seems very cumbersome to maintain the class when errors are added, moved around, or deleted. It would be very nice not to worry about values. Instead of:
class Error: onerror = 1 anothererror = 2 theother = 3 bigone = 24 baderror = 25
etc.
I'd prefer to have
errors = """ onerror=1, anothererror, theother, bigone = 24, baderror, """ Error = enum(errors)
and let the enum class worry about the values.
I was always reluctant to using enums because enumerations are just a convenience and I didn't want to add any more overhead. I ran into Will Ware's post in comp.lang.python about enums and decided to try it. I thought that the list arguments to the enum class were too cumbersome for my taste, and therefore, updated it to use a string instead. Later on, I removed as much as possible from the class to keep the overhead down.
The enum class simply creates a dictionary, just like the Error class would've, but it automatically assigns the values. The enum class ends up parsing the string and creating copies of what it needs (through strip()). I place 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.
The main thing I like about this implementation is that when the enum string is between multi-line string delimiters, editing the enum definition is identical to editing C code, except for comments. I thought about parsing comments but decided against it because of the additional overhead.
Simple solution with python2.2 __metaclass__.
The _meta_enum.__init__ needs check uniqueness of values and should acquire inherited values from eventual parent classes!