PEP 435 Accepted – Adding an Enum type to the Python standard library
python.org
python.org
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.
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 :)
IntEnum values behave like integers in other ways
you'd expect:
>>> int(Shape.circle)
1
>>> ['a', 'b', 'c'][Shape.circle]
'b'
>>> [i for i in range(Shape.square)]
[0, 1]
[1] http://www.python.org/dev/peps/pep-0435/#intenum >>> Color.red
<Color.red: 1>
So when you print out an enumeration, you get its name instead of just the number. This can be a big deal for debugging e.g. OpenGL code, which has a lot of enumerations. Which of the following would you prefer? >>> gl.getError()
1286
Or would you prefer, >>> gl.getError()
<gl.INVALID_FRAMEBUFFER_OPERATION: 1286>http://www.python.org/dev/peps/pep-0435/#functional-api
Having to throw in a " ".join(...) isn't that bad.
> It can be a whitespace-separated string of names, a sequence of names, a sequence of 2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to values.
>>> 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.
It's weird, unnecessary, it just shouldn't be there.
Personally, I would've preferred:
>>> Enum('Example', 'foo', 'bar', 'baz')
(ie. Enum(name, *values))
* 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.
>>> Animal = Enum('Animal', ('lion', 'tiger', 'liger', 'tigon'))
Now all I want in Python is a real switch statement...
Incidentally, this makes me wonder if one could implement something similar for flags (powers of two values, overloading | and &). Though sets of enums might be sufficient.
Perhaps you're thinking of static versus dynamic typing?
Python functions are always 'a -> 'b (any to any), the weakest possible type for a function. Same for variables (as opposed to values), they are all 'a; same for list membership or attribute membership. There is no place in the language with room for a nullable / nonnullable distinction.
A dynamically-typed language is one in which only values have types, and there are no restrictions by type on what values may be bound to particular names. Expressions may or may not have defined types, and may or may not check these types (some dynamically-typed languages do allow statements to be made about the types of functions, for example; some use these in a "static-y" way, while others treat them more as hints for runtime optimization).
Strong and weak typing are far less precisely defined. The most broadly-used criterion I've personally seen is that in a strongly-typed language, attempting to perform an operation with values whose types are incompatible with the operation will fail immediately, and will not try to implicitly coerce the values to acceptable types for the operation.
Python is generally considered strongly typed, and dynamically typed. There is no consensus that these two labels are incompatible, just as there is no consensus that weak and static typing are incompatible (C is often described as being both statically and weakly typed, for example, due to C's casting and conversion facilities).
1 + True == False + 2
It should have to be: 1 + int(True) == int(False) + 2Which means there's no coercion or conversion going on here. For what you think it "should" be, Python would have to break Liskov substitution for subclasses of int.
Here's to Python 4!
http://pythonpath.wordpress.com/2012/01/26/python-enum-with-...
I now see some good uses for Enum, but (with a skeptical eye to additions) I believe that the reasons to keep the language/libs small are equally important.
1. Making the integral values of an enum clear and unchanged by re-ordering the names. If the integral values matter to you (because you serialize enums that way), then I would want them to be explicit.
2. The integer values of these enums aren't exclusive. Two enums can reference the same value.
That said, I agree a short hand for people who don't care seems reasonable, where the integers could be auto-assigned by definition order, or just all set to 0.
class Colors:
red, green, blue = range(3) class Colors(Enum):
red, green, blue = range(3) red, green, blue = itertools.count()
work too? >>> Animal = Enum(['ant, 'bee', 'cat', 'dog'])
>>> Animal.ANT
'ant'
I'm not convinced it's useful to pass the class name into the functional API, but I would see value in having an easy API to create enumerated strings. It's easier to see what's going on in other environments (e.g. in a datastore, or in JavaScript) if you pass around string identifiers instead of ints.Here's the class I've been using to do that:
class Constants(object):
def __init__(self, names, enum = False):
self._names = frozenset(names)
if enum:
for (i, name) in enumerate(self._names):
setattr(self, name.upper(), i)
else:
for name in self._names:
setattr(self, name.upper(), name.lower())
self.frozen = True
def keys(self):
return [name.upper() for name in self._names]
def values(self):
return [getattr(self, name.upper()) for name in self._names]
def __setattr__(self, key, value):
if getattr(self, 'frozen', False):
raise Exception("Constants cannot be modified after instantiation")
else:
object.__setattr__(self, key, value)
Example: >>> ImportMethod = Constants(
>>> [
>>> 'email',
>>> 'manual_upload',
>>> 'api',
>>> ]
>>> )
>>>
>>> print(ImportMethod.API)
'api' class Keys(Enum):
space = 1
esc = 2
enter = 3
return = 3 # Alias to "enter".
Also, less magic.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.
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?
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...
My memory could be a little faded on this though, I haven't coded in Java in a few years..
I think what you mean though is that in 99.9% of cases a user of a Java enum never needs to (or shouldn't) refer to the ordinal value.
Examples from C#:
http://msdn.microsoft.com/en-us/library/vstudio/cc138362.asp...
It's also used to be sort of useful for serialization or storing them in a DB as they'd take up less space than a string, but these days that's not so important and I'd actually caution against it.
Basically you don't need it often, but when you do it's extremely useful.
class UniqueValue: pass
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 ?Unless this is changed in Py 3, I still don't understand how this works.
class OrderedClass(type):
@classmethod
def __prepare__(metacls, name, bases, **kwds):
return collections.OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class A(metaclass=OrderedClass):
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
>>> A.members
('__module__', 'one', 'two', 'three', 'four')
[1] http://docs.python.org/3/reference/datamodel.html#metaclass-... def enum(*args):
return dict(zip(args, range(len(args))))
colors = enum('red', 'green', 'blue')
# {'blue': 2, 'green': 1, 'red': 0}+ 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?
Didn't Python 3 do more removing/tidying up than actually adding of stuff?
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.
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... from collections import namedtuple
myenum = namedtuple('myenum', ['a', 'b', 'c'])(range(3))
myenum.a == myenum.aPython may defer its type checking to run time, but it still has it.
It's still useful to have mnemonic names for special values, with nice string representations and some guarantees on what is equal to what.
http://docs.python.org/3/reference/datamodel.html#objects-va...
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.Anyone know the motivation for this? Seems like a source of frustration to me.
(the next paragraph gives you the __members__ ordered dict, if you want to iterate on something else)
[1] http://bazaar.launchpad.net/~barry/flufl.enum/trunk/view/hea...
We may create a almost-compliant back-port for 2.7 as an external library though