[Tutor] What would be good use cases for the enum module?

Steven D'Aprano steve at pearwood.info
Sun Apr 9 00:13:24 EDT 2017


On Sat, Apr 08, 2017 at 10:00:21PM -0500, boB Stepp wrote:
> After reading some discussion on the Python main list about the enum
> module and some suggested changes, I thought I would read the docs on
> it at
> https://docs.python.org/3/library/enum.html?highlight=enum#module-enum
[...]
> And I am having an even harder time imagining what I would want to use
> Enum for if I don't care about the values assigned to the names and
> use auto to automatically assign values.  I am having a real crisis of
> imagination here!  Anyone with some commonplace and practical
> applications of the enum module?

Have you read the PEP for the enum module? There's also an earlier, 
rejected PEP:

https://www.python.org/dev/peps/pep-0354/

https://www.python.org/dev/peps/pep-0435/

There are a few uses for enums where they have to behave like ints for 
compatibility with code following C conventions, but basically an enum 
is an abstract symbol with a pretty representation to make debugging 
easier.

For example, suppose I have a function that justifies a paragraph of 
text:

def justify(paragraph, where):
    ...

where the `where` argument specifies whether to justify the text on the 
left, on the right, in the centre, or fully justified on both sides. One 
way to specify that is to use numeric constants:

if where == 1:
    # justify on the left
elif where == 2:
    # justify on the right
elif where == 3:
    # justify in the centre
elif where == 4:
    # fully justify at both ends

but there's no connection between the numbers I choose and the type of 
justification. I could just have sensibly used -3, 87, 4 and 32.5 as 1, 
2, 3 and 4.

A bit better is to use strings:

if where == 'LEFT':
    # justify on the left
elif where == 'RIGHT':
    # etc

which at least now is self-documenting, but it suggests that the `where` 
argument might take any string at all, which is not correct. There are 
only four fixed values it can take. And besides, having to use the 
quotation marks is tiresome.

So let's invent four (or even five, for Americans) named constants:

LEFT = 'LEFT'
RIGHT = 'RIGHT'
CENTRE = CENTER = 'CENTRE'
FULL = 'FULLY JUSTIFIED'


Now we're getting closer. The caller can say:

text = justify(some_text, CENTRE)

which is nice, and the justify() function can include:

if where == LEFT:
    ...

without quotation marks, which is also nice. That solves about 95% of 
the problem.

The last niggly 5% is a subtle thing. Because the constants are strings, 
we might be tempted to do string things to them, either deliberately or 
by mistake:


justification_mode = CENTRE.lower() + LEFT[1:]  # Oops!
# much later
justify(some_text, justification_mode)


which of course will fail, but it will fail *when the string is used*, 
not when you do the string-stuff to those constants. It would be nice if 
it failed straight away, at the "justification_mode" line.

To fix that, we need something which looks like a string when you print 
it, for debugging, but actually isn't a string, so it doesn't accept all 
the usual string methods. That's effectively just an abstract symbol, 
and the way to get this in Python is with an enum.

Enums have a few other nice properties, which you may or may not care 
about, but the primary use is to act as set of related named symbols.



-- 
Steve


More information about the Tutor mailing list