faqts : Computers : Programming : Languages : Python : Snippets

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

4 of 7 people (57%) answered Yes
Recently 2 of 5 people (40%) answered Yes

Entry

Enumeration (was: Parsing chemical formula)

Mar 9th, 2005 11:56
Martin Miller, Nathan Wallace, Hans Nowak, Snippet 19, Christian Tismer


"""
Packages: basic_applications.enumeration
"""

"""
> > > NAME, NUM, LPAREN, RPAREN, EOS = range(5)
> >
> > As I see this idiom of creating ENUM-alike constants
> > appear again (see doctest), this deserves an entry in
> > some howto. Tim, when did you start using it?
> > Very elegant.
> 
> It's a neat idiom. I'm not sure where I got it from (I've used it too),
> but I recall a while back I was pondering the problem. You see, I hate
> counting, and one needs to *count* to do this trick with range. C's
> 'enum' doesn't have this problem. So I tried to figure out an elegant
> way to do something like:
> 
> enum(NAME, NUM, LPAREN, RPAREN, EOS)
> 
> but couldn't come up with anything that worked well. The main problem is
> of course that NAME etc simply aren't defined, so you get an exception.
> You can catch that exception of course, and then define, but so far
> that's still a kludge.
> 
> Perhaps: enum('NAME', 'NUM', 'LPAREN', 'RPAREN', 'EOS') could
> work..still, that is too much typing. :)
> 
> Of course this doesn't belong on tutor but in the newsgroup, really, but
> I felt so much mental exertion on my part deserved some mention
> somewhere, and this was a good opportunity. :)

:-))

Well, how 'bout this? 
You can even save to type those ugly commas:
"""

def enum(tokens, base=0):
	import string
	lis = string.split(tokens)
	g = globals()
	for i in range(len(lis)):
	    g[lis[i]] = i+base

enum("ONE TWO THREE", 1)
print ONE, TWO, THREE
# (1, 2, 3)

==================
Slight Enhancement:

You can make the above generate identifiers that know their names, which
can be useful when printing or otherwise displaying their values.

class _NamedInt(int):
    def __new__(cls, value=0, name=None):
        inst = int.__new__(cls, value)
        inst.name = name
        return inst

    def __str__(self): return self.name
    __repr__  = __str__

def enum(tokens, base=0):
    lst = tokens.split()
    gbls = globals()
    for i, name in enumerate(lst):
        gbls[name] = _NamedInt(i+base, name)

enum("ONE TWO THREE", base=1)
print "print ONE, TWO, THREE:", ONE, TWO, THREE
print "type(ONE):", type(ONE)
print "ONE: str = %s  repr = %r" % (ONE, ONE)
print "TWO: str = %s  repr = %r" % (TWO, TWO)
print "THREE: str = %s  repr = %r" % (THREE, THREE)
print "\nafter assignment 'var = TWO'"
var = TWO
print "var: str = %s  repr = %r" % (var, var)
print "var == 2: %r" % (var == 2,)
print "var == TWO: %r" % (var == TWO,)
print "var is TWO: %r" % (var is TWO,)
print "var is 2: %r" % (var is 2,)
print "TWO is 2: %r" % (TWO is 2,)

# print ONE, TWO, THREE: ONE TWO THREE
# type(ONE): <class '__main__.NamedInt'>
# ONE: str = ONE  repr = ONE
# TWO: str = TWO  repr = TWO
# THREE: str = THREE  repr = THREE
#
# after assignment 'var = TWO'
# var: str = TWO  repr = TWO
# var == 2: True
# var == TWO: True
# var is TWO: True
# var is 2: False
# TWO is 2: False