

PEP 435 Accepted – Adding an Enum type to the Python standard library - randlet
http://www.python.org/dev/peps/pep-0435/

======
e1ven
Can someone help me understand how this helps? I'm only a mediocre programmer,
and I'm having trouble understanding the implications.

It seems like you declare these like any other class. So what's the difference
between this, and creating a class full of ints?

If I have class Color: red = 1 blue = 2

etc, wouldn't I get the same thing?

Is the difference that you don't need to instantiate an instance of it?

I know I'm being dense, and I've read the PEP, but it's not quite clicking
yet.

~~~
famousactress
In this case, the attributes are not ints.. so If you defined that class
functions that took it's attributes would need to accept an int, and if I
passed max-int or something it'd be up to your function to go figure out
whether my argument was a valid value for Color.

The enum class gives you that stuff. The argument you'd expect would be
instanceof(arg, Color) == True (I think that's how they did it) and if it was,
you'd be assured that the value was a valid value for Color.

So you could do it yourself, sure.. but to get all the little benefits, you'd
have to do more coding than naming a bunch of ints in a new class.. It's
subtle though. Not a wild game-changer or anything :)

~~~
e1ven
Thanks.. That makes sense.. And I suppose it also helps satisfy the "explicit
is better than implicit" edict, by making it clearer what you are doing.

------
comex
The syntax strikes me as somewhat strange. It requires writing out enum values
(and thus avoiding duplicates or, for a cleaner look, just keeping them
sorted), necessitating unnecessary effort when new values are added in the
middle, and misleadingly implies that the enum values are merely class-level
integer constants. I would have preferred a more explicit API that used a list
of strings for the enumerators.

~~~
oellegaard
I completely agree, this disgusts me:

>>> Animal = Enum('Animal', 'ant bee cat dog') >>> Animal.ant <Animal.ant: 1>

That being said, I welcome enums - I made classes to basically represent an
enum a bunch of times.

~~~
eliben
What disgusts you about it, in particular?

~~~
ekimekim
The fact that it allows whitespace-seperated words. It's just wrong.

It's weird, unnecessary, it just shouldn't be there.

Personally, I would've preferred:

>>> Enum('Example', 'foo', 'bar', 'baz')

(ie. Enum(name, *values))

~~~
eliben
That syntax is a bit unusual, but it has the clear advantage of being far less
verbose. Consider this:

* The functional API is mostly for short code snippets and experiments in the shell. For real programs, the standard class syntax is preferred and recommended. * namedtuple already uses the same functional API allowing space-separated members, and it's a popular tool in the stdlib. Yes, the first time you run into it it feels a bit odd, but then you get used to it and it's not a big deal.

------
randlet
Guido's approval message: [http://mail.python.org/pipermail/python-
dev/2013-May/126112....](http://mail.python.org/pipermail/python-
dev/2013-May/126112.html)

~~~
gbin
I prefer the Michael Ford proposed syntax and would gladly port the
implementation if possible. Having to specify either an ordinal number like in
BASIC of 1980 or have to specify symbols as strings looks dodgy to me.

~~~
Tobu
Since Enums are mostly unmagical (apart from the member wrapping), you can use
a compact syntax:

    
    
      class Colors(Enum):
          red, green, blue = range(3)

~~~
iso8859-1
will

    
    
        red, green, blue = itertools.count()
    

work too?

~~~
Tobu
If it works in a Python shell, it will work for an enum (this doesn't).

------
adrianmsmith
I don't think that enums should have values (i.e. numbers).

Nearly every language does it that way but isn't that just because C
originally implemented enums with numbers? Modern languages are much higher
level.

Java enums don't have any numeric equivalent value, they are just objects,
with textual names if you must convert them into something more primative.

~~~
Nursie
Efficiency/speed?

The user doesn't necessarily need to have access to the raw numbers I guess,
but when it comes down to comparisons/branching etc, numbers are pretty much
always going to be fastest and simplest.

And if they _are_ going to be based on numbers underneath, why not let the
user/coder/whatever have access to them?

~~~
mikeash
Everything is numbers underneath, so you could ask the same question about all
data types. For example, if pointers are going to be based on numbers
underneath, why not let the programmer have access to them? Lots of good
reasons, actually, which is why most languages don't provide that access. Many
of those reasons apply to enumerations too.

~~~
Nursie
Well, you've outed me as a C programmer there I guess :)

I don't really subscribe to the idea that languages should force people onto
rails. I love higher level languages for their rapid development of course,
and the high level constructs. But there's something about being able to get
your hands dirty, right in the guts of a problem...

------
marmaduke

      Enumerations support iteration, in definition order:
      
      >>> class Shake(Enum):
      ...   vanilla = 7
      ...   chocolate = 4
      ...   cookies = 9
      ...   mint = 3
      ...
      >>> for shake in Shake:
      ...   print(shake)
      ...
      Shake.vanilla
      Shake.chocolate
      Shake.cookies
      Shake.mint
    

Python's execution model sez that the class declaration is nothing more than
code that is exec'd in a dictionary. We know that Python dictionaries do not
perserve order, so why is this iteration in definition order possible, barring
modification to the interpreter or dict type ?

~~~
eliben
It's possible by using a __prepare__ method in the metaclass of Enum, which
allows to return an essentially ordered dict for the __dict__ of enumeration
classes.

~~~
marmaduke
I guess this is new to Py 3k? Thanks for the tip!

~~~
paul_odin
Right, PEP 3115. Indeed one of the reasons is that "there is an important body
of use cases where it would be useful to preserve the order in which a class
members are declared."

<http://www.python.org/dev/peps/pep-3115/>

------
jjs
Python has been getting bloated in recent years. Why not just do the
following?

    
    
      def enum(*args):
          return dict(zip(args, range(len(args))))
    
      colors = enum('red', 'green', 'blue')
    
      # {'blue': 2, 'green': 1, 'red': 0}

~~~
pavpanchekha
There are a few things this proposal does that improves upon yours:

\+ Enum values of different types are incomparable. This is widely seen as a
good thing. \+ Enum values are instances of their Enum; this allows more
flexibility in user code. \+ As a result of the above, you can have a
dictionary without Enum values of two different types colliding. \+ Enum
values print in a more friendly way. This is expected to help debugging. \+ To
support the above, enum values know their own name. This is likely helpful
both for debugging and for various introspection hacks. \+ Enums can be
iterated over in a fixed order. This allows automated help systems and similar
to maintain consistency between runs, improving user experience. \+ There's a
lot more error checking provided to avoid cases like defining the same enum
value twice.

But I understand your sentiment. We always enjoy smaller languages because it
helps us keep them in our heads. But note that Enums aren't a new language
feature -- this PEP simply adds another module to the standard library. The
code your provide, flawed as it is, is still a pattern common to many
different libraries, so it would be good to put it into the stdlib; but if
we're doing that, might as well do it right, don't you think?

~~~
jjs
Fair enough. The enums themselves aren't a problem; they just seem symptomatic
of a pile-on-more-stuff mentality.

------
nilsbunger
When will this ship in python? I don't know a lot about the typical time
between a PEP acceptance and a release containing the feature.

~~~
eliben
We expect the implementation will be committed in the next few weeks, and
you'll be able to give it a try using Python's tip revision ("trunk"). It will
actually _ship_ with Python 3.4

------
morpher
Interesting that this is PEP 435 and the prior attempt was PEP 354.

~~~
aleyan
The permutations will continue until the PEP improves.

~~~
eliben
Yes, I noticed that curiosity :-) Not intentional!

Luckily there's no need for more permutations - this PEP was accepted. I
expect PEPs 534 and 543 to surface at some point, but it isn't likely they
will deal with enums.

------
nobodysfool
Stupid me, I was using enums the wrong way. I was using an enum like a
constant.

I.E. If my database takes a 'Sex' parameter, with Male as 1, Female as 2,
Unknown as 3, Both as 4 - I'd use an enum like so:

    
    
        update person set sex=Sex.Male
    

Looks like I can't do that with this enum class. Well, I suppose I'd have to
do it like so:

    
    
        sex = Sex.Male.value
    

not very sexy...

~~~
bsimpson
Wouldn't IntEnum fit your case better?

------
herge
Could you not use mock.sentinel values as an enum? Also, you can create a poor
man's enum from 2.7+ with:

    
    
        from collections import namedtuple
        myenum = namedtuple('myenum', ['a', 'b', 'c'])(range(3))
    
        myenum.a == myenum.a

~~~
viscanti
That's not even a poor man's enum, it's just an enum. Named tuples can be used
for everything an enum can be. This doesn't seem like a necessary PEP, but
I've made my peace a long time ago about Python's bloated standard library.
It's not the end of the world, and I still love Python, but this doesn't seem
necessary to me.

~~~
iso8859-1
You don't have methods and you don't have a proper repr(). Also, even if you
don't assign numbers, the fields are still ordered (which they shouldn't be).

------
yen223
What purpose would Enums serve in a dynamically-typed language?

~~~
oellegaard
Even though dynamically typed, it still have the concept of types. There are
good examples on how it works in the PEP.

~~~
jerf
And more the the point, Python is strongly typed in the sense that it has very
few automatic conversions between types, in contrast to, say, Perl. As the PEP
says, this means that you can't accidentally compare an enum value of one type
to an enum value of another without a runtime error occurring, instead of an
infuriatingly subtle bug.

Python may defer its type checking to run time, but it still has it.

------
ajanuary
> Iterating over the members of an enum does not provide the aliases

Anyone know the motivation for this? Seems like a source of frustration to me.

~~~
Tobu
The aliases aren't part of the enum, if you think of the enum as a set of
values. Iterating is done on the values, not the names.

(the next paragraph gives you the __members__ ordered dict, if you want to
iterate on something else)

------
lmm
Seems a bit dodgy that enum values can be _any_ value. What happens if you use
mutable values and later change them to be the same?

~~~
dvanduzer
Objects can be mutable or immutable. The value of a mutable object can change
to another value, but it's not that the _value-in-itself_ is mutable.

[http://docs.python.org/3/reference/datamodel.html#objects-
va...](http://docs.python.org/3/reference/datamodel.html#objects-values-and-
types)

~~~
lmm
So can I declare an enum value to be e.g. a list? Is that value "frozen" when
the enum declaration is processed or what?

~~~
dvanduzer
A list is not a value, it is a type of object. The second to last paragraph of
the section in the reference manual I linked may help:

    
    
      Some objects contain references to other objects; these are called
      containers. Examples of containers are tuples, lists and dictionaries. The
      references are part of a container’s value. In most cases, when we talk
      about the value of a container, we imply the values, not the identities of
      the contained objects; however, when we talk about the mutability of a
      container, only the identities of the immediately contained objects are
      implied. So, if an immutable container (like a tuple) contains a reference
      to a mutable object, its value changes if that mutable object is changed.
    

PEP-435 says enums are bound to "unique, constant values" -- not that you can
bind enums to arbitrary types of objects.

------
dschep
Barry gave a good talk about this at DCPython on Tuesday.

------
Toshio
Interesting. It looks like if you want to use enum in 2.7 you have to use a
package called flufl[1].

[1]
[http://bazaar.launchpad.net/~barry/flufl.enum/trunk/view/hea...](http://bazaar.launchpad.net/~barry/flufl.enum/trunk/view/head:/flufl/enum/_enum.py#L170)

~~~
eliben
flufl.enum was the initial candidate for PEP 435, but the current approach
changed and uses implementation techniques not available in Python 2.7

We may create a almost-compliant back-port for 2.7 as an external library
though

~~~
tshepang
You sure it's not better spending the energy elsewhere? Python 3 needs more
exclusive features to encourage people to migrate from Python 2.

