
On Wed, Jul 27, 2011 at 8:57 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Thu, Jul 28, 2011 at 12:21 PM, Guido van Rossum <guido@python.org> wrote:
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.
Yeah, a similar discussion came up in the context of defining namedtuple instances a while back (I don't recall if you were part of that conversation or not - IIRC, the thread started off on the topic of assignment decorators and ended up wandering down this road at some point)
I recall that, and I think I even contributed. But I agree we never came up with anything acceptable.
Most proposed solutions relied on some form of abuse of the def statement to define arbitrary objects that knew their own name. For example:
def red from namedvalue(1) # Rather unnatural phrasing def red as namedvalue(1) # Phrasing is natural, but the name is on the wrong side of the 'as' def red = namedvalue(1) # Simple assignment may not suggest enough magic def as red = namedvalue(1) # Syntax soup! as red def namedvalue(1) # Just throw keywords at the screen and see if anything sticks red def= namedvalue(1) # An alternative inspired by augmented assignment def red << namedvalue(1) # Arbitrary but suggestive
A protocol would then be defined to make that work (regardless of the specific syntax). Either the actual call would be transformed into "namedvalue('red', 1)" (which has the virtue of working with existing objects like collections.namedtuple, but prevents provision of useful default behaviour) or else there would be a new protocol like "obj.__named__(name)", with a fallback to something like the NamedValue recipe if __named__ wasn't defined (which has the virtue of working with arbitrary objects as in "def red as 1", but requires adapter classes to work with existing APIs like namedtuple).
The bikeshed was painted many different colours before the thread finally wound down without achieving any kind of resolution. I suspect this may end up being another PEP 308, where the only way it will ever happen is if *you* find a syntax you like (or are at least willing to tolerate in order to gain the functionality).
My current thinking would be that you could probably hack it in CPython through bytecode inspection: find the STORE_FAST or STORE_GLOBAL opcode right after the CALL_FUNCTION opcode, and see what to name it assigns. This is of course terrible, depending on all sorts of implementation stuff, but we might create a builtin function that returns that variable name, assuming the scope is module-global or a class scope. I know it sounds atrocious, but the alternative is requiring extra mark-up and a hidden implied argument, which does not sound good either. (Maybe extra mark-up could be required for the proposed new builtin to work.)
Adding an int-specific Enum class eliminates a lot of the use cases for a "named object" feature, which is the main reason I'm trying to hold out for the more general functionality - I still have hope that we'll strike on a syntax for named assignments that is clear enough and clean enough that none of the core devs actively oppose it.
I agree that named constants don't have to be ints -- though for most types other than ints, my main requirement for enums (that they print themselves nicely) is not an issue. Regarding Ben Finney's requirement that enums primarily define unique values and that enums from two different classes must compare unequal even if their int values are equal, I really don't care about that. You can use isinstance() if you want to check that. -- --Guido van Rossum (python.org/~guido)