
On Wed, Jul 27, 2011 at 6:12 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Thu, Jul 28, 2011 at 10:56 AM, Barry Warsaw <barry@python.org> wrote:
Again, looking at how I've used them extensively over the last several years, I would much rather write
class Colors(Enum): red = 1 green = 2 blue = 3
than
red = NamedValue('red', 1) green = NamedValue('green', 2) blue = NamedValue('blue', 3)
To me, the duplication is jarring and error prone.
Agreed, especially in new code, when you just want to get the names defined, and you don't have to worry about compatibility. I think that's why NamedValue would often be wrapped by an enum class. But there is the downside that, for all the elegance of writing class Color(enum): red = 1 ... all the *uses* of colors have to write foo.Color.red instead of foo.red.
Yeah, I'd actually be inclined to define such values programmatically rather than writing them out manually like that:
_named_colours = dict( red=0xFF0000, green=0x00FF00, blue=0x0000FF, ) globals().update((k, namedvalue(k, v)) for k, v in _named_colours)
Eek, no! It will take the average reader way too long to figure out that that does. Static analyzers (which are getting more important) are likely to be fooled by it too. Please remember EIBTI.
(where namedvalue is the value based factory function I mentioned in the recipe post)
However, my contention is that the fundamentally interesting operation is associating names with values (as your EnumValue class does). Enums and their ilk are then just syntactic sugar for defining groups of such values without needing to repeat yourself.
It's just possible that there's no way to define enums that neither introduced a new (class) scope nor requires a lot of redundant typing. I wish I could write red = Enum(1) and it made the following true: assert red == 1 assert isinstance(red, int) # a subclass assert str(red) == 'red' But we'd first need a non-hacky way for Enum() to know that it is being assigned to something named 'red'. I have a few other use cases for that as well, e.g. a Property class for App Engine that doesn't require a metaclass to patch up the value. A half-solution would be if naturally the definition of red appeared inside some other class (not a class specially created for the enum, but a class that has other functionality) and somehow a mix-in metaclass (if such a beast exists) would pass in the name once the class is being defined. But if you want module-level enum values you'd still have to do something like class Color(Enum): red = 1 ... red, green, blue = Color.red, Color.green, Color.blue That's not ideal since the next programmer could add a new color but forget to also pull it into the outer scope. And no, I don't like solutions based on globals()... TBH, I'm not sure we should hold our breath until we have the perfect solution. Looking over flufl.enum again, I like most of its design decisions except the "enums are not integers" part. For me, after the above definition of class Color, I'd be happy of Color.red == 1, as long as str(Color.red) == 'red'. (Here I am consistent with the behavior of True and False.) If you want the enum values to appear at the module level (e.g. socket constants?) pulling them up a level explicitly, while not ideal (see above), is not the end of the world either. -- --Guido van Rossum (python.org/~guido)