classy enumerations

2014-02-17

An enumeration is a term that usually refers to a type consisting of a finite number of distinct members. The members themselves can be tested for equality, but usually their particular value is not important.

Maybe you’re modelling a Sphex wasp and you have a state variable with values NOTNEARHOME, JUSTLEFTHOME. You could represent that with an enumeration.

In C the enum keyword assigns (usually small) integers to constant identifiers. It is problematic, chiefly because the members of the enumeration are really just integers. After enum { Foo; }, then code like Foo / 5 is valid (note: valid, not sensible).

In Python you could do essentially the same thing:

NOTNEARHOME = 0
JUSTLEFTHOME = 1

if self.state == NOTNEARHOME:
    if 'spider' in self.inventory:
        # head towards home
    else:
        # look for juicy spiders

You do see this style (ast.PyCF_ONLY_AST Note 1), but it has the same problems as enum in C. The values are just integers (so, for example, print self.state will print 0, or 1).

You could use strings (like decimal.ROUND_HALF_EVEN):

NOTNEARHOME = 'notnearhome'
# and so on...

That’s better because now I might have a clue if a print out a value and it’s 'notnearhome', but it’s only a little bit better, because you still might accidentally use the value innappropriately (opt = decimal.ROUND_HALF_EVEN; opt += 'foo').

I have a proposal:

Use a class!

class NOTNEARHOME: pass         # Note 2
class JUSTLEFTHOME: pass

Let’s call this classy enumerations.

Classy enumerations have the advantage that we don’t need to manually assign numbers or strings. Values like Mood.PUZZLED and Mood.CONFUSED (which are actually classes) will be unique, so can be tested using == or is correctly.

With classy enumerations we get an error if we accidentally use them in an expression:

>>> PUZZLED+1
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported operand type(s) for +: 'classobj' and 'int'

And to wrap up:

class True: pass
class False: pass

This article was inspired by looking at some of Peter Waller‘s code who seems to have invented the idea of using classes for enumerations.

Note 1

Yes this value matches a value in the C header file. Maybe that has some merit, but it doesn’t make for a very Pythonic interface.

Note 2

The body of a class definition is just a block of code. When that body is just a simple statement, it can share the line with the class declaration. Hence, class NOTNEARHOME: pass is a compact complete class definition. If you’re in a mood for documentation, replace “pass” with a docstring.

About these ads

3 Responses to “classy enumerations”

  1. macfreek Says:

    Note that Python 3.4 (which is expected to be released by the end of this week) has a build-in enum type. See http://www.python.org/dev/peps/pep-0435/. It’s implemented as attributes, not as classes. If you’re interested, PEP 354, a previous proposal for enums in Python which was rejected, lists a few more alternatives (I don’t think classes are one of them).

    • drj11 Says:

      Interesting.

      Having read PEP 354 my first question is whether I can go:

      class Sphexy(Enum):
        class GoneHome: pass
        class Wandering: pass
      

      I’ll try it out when 3.4 lands.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: