Am I the only one who would love these extentions? - Python 3.0 proposals (long)

Alex Martelli aleax at aleax.it
Tue Nov 11 16:07:46 CET 2003


Alexander Schmolck wrote:
   ...
>> > AND, ASSERT, BREAK, CLASS, etc == "AND, ASSERT, BREAK, CLASS,
>> > etc".split(", ")
>> 
>> Unfortunately, this breaks the "once, and only once" principle: you
>> have to ensure the sequence of words is the same on both sides -- any
>> error in that respect during maintenance will cause small or big
>> headaches.
> 
> True, but I'd still prefer this one (+ editor macro) in most cases to
> (ab)using numbers as symbols (this was my main point; I'm sure I could

I'm used to take bus 20 to go downtown.  And perhaps some of my ancestors
fought in the VII Legio (also known by nicknames such as Gemina and Felix,
and not to be confused with the _other_ VII Legio, also known as Claudia
and Pia).  If using numbers just as arbitrary tags used to distinguish 
items is "abuse", then there's been enough of that over the last few
millennia -- and there's by far enough of it in everyday life today --
that to keep considering it "abuse" is, IMHO, pedantry.

All the more so, when we also want our "tags" to have _some_ of the
properties of numbers (such as order) though not all (I'm not going
to "add" buses number 20 and 17 to get bus number 37, for sure).

> also think of various hacks to avoid the duplication and do the the
> stuffing in the global namespace implicitly/separately -- if it must go
> there at all costs). The main advantage the above has over custom enum
> types is that it's immediately obvious. Maybe the standard library should
> grow a canonical enum module that adresses most needs.

"A canonical enum module" would be great, but the probability that a
design could be fashioned in such a way as to make _most_ prospective 
users happy is, I fear, very low.  Anybody's welcome to try their hand
at a pre-PEP and then a PEP, of course, but I suspect that enough
consensus on what features should get in will be hard to come by.


>> Keeping enum values in their own namespace (a class or instance) is
>> also generally preferable to injecting them in global namespace,
>> IMHO.
> 
> Yep, this would also be my preference. I'd presumably use something like
> 
>   DAYS = enum('MON TUE WED [...]'.split())
> 
> maybe even without the split.

Sure, if you have an 'enum' factory function or type you may choose
to have it do its own splitting.  But if DAYS.MON and DAYS.WED are
just strings, so you cannot _reliably_ test e.g. "x > DAYS.WED" in
the enumeration order, get "the next value after x", and so on, then
I fear your enum will satisfy even fewer typical, widespread
requirements than most other proposals I've seen floating around
over the years.


>> If you want each constant's value to be a string, that's easy:
> 
> Doesn't have to be, strings are just the simplest choice for something
> with a sensible 'repr' (since you might want some total order of your
> enums a class might be better -- if one goes through the trouble of
> creating one's own enum mechanism).

I don't think a repr of e.g. 'TUE' is actually optimal, anyway --
"DAYS.TUE" might be better (this of course would require the enum
builder to intrinsically know the name of the object it's building --
which again points to a metaclass as likely to be best).

But representation has not proven to be the crucial issue for enums in 
C, and this makes me doubt that it would prove essential in Python; the
ability to get "the next value", "a range of values", and so on, appear
to meet more needs of typical applications, if one has to choose.  Sure,
having both (via a type representing "value within an enumeration")
might be worth engineering (be that in a roll-your-own, or standardized
PEP, for enum).

I _think_ the rocks on which such a PEP would founder are:
-- some people will want to use enums as just handy collections of
   integer values, with the ability, like in C, to set FOO=23 in the
   middle of the enum's definition; the ability to perform bitwise
   operations on such values (using them as binary masks) will likely
   be a part of such requests;
-- other people will want "purer" enums -- not explicitly settable to
   any value nor usable as such, but e.g. iterable, compact over
   predecessor and successor operations, comparable only within the
   compass of a single enum;
-- (many will pop in with specific requests, such as "any enum must
   subclass int just like bool does", demands on str and/or repr,
   the ability to convert to/from int or between different enums,
   and so on, and so forth -- there will be many such "nonnegotiable
   demands", each with about 1 to 3 proponents);
-- enough of a constituency will be found for each different vision
   of enums to make enough noise and flames to kill the others, but
   not enough to impose a single vision.

This may change if and when Python gets some kind of "optional
interface declarations", since then the constraints of having enums
fit within that scheme will reduce the too-vast space of design
possibilities.  But, that's years away.


>> class myenum(Enum):
>>     AND = ASSERT = BREAK = CLASS = 1
>> 
>> with:
>> 
>> class Enum: __metaclass__ = metaEnum
>> 
>> and:
>> 
>> class metaEnum(type):
>>     def __new__(mcl, clasname, clasbases, clasdict):
>>         for k in clasdict:
>>             clasdict[k] = k
>>         return type.__new__(mcl, clasname, clasbases, clasdict)
> 
> Yuck! A nice metaclass demo but far too "clever" and misleading for such a
> simple task, IMO.

I disagree that defining an Enum as a class is "clever" or "misleading"
in any way -- and if each Enum is a class it makes a lot of sense to use
a metaclass to group them (with more functionality than the above, of
course).  Of course, values such as 'myenum.ASSERT' should be instances
of myenum (that is not shown above, where I made them strings because
that's what you were doing -- the only point shown here is that there
should be no duplication).


>> The problem with this is that the attributes' _order_ in the
>> classbody is lost by the time the metaclass's __new__ runs, as
>> the class attributes are presented as a dictionary.  But if the
>> values you want are strings equal to the attributes' names, the
>> order is not important, so this works fine.
>> 
>> But many applications of enums DO care about order, sigh.
> 
> If that prevents people from using the above, I'd consider it a good thing
> ;)

Oh, it's not hard to substitute that with e.g.

class myenum(Enum):
    __values__ = 'AND ASSERT BREAK CLASS'.split()

(or, ditto w/o the splitting) so that order is preserved.  But then
we have to check explicitly at class creation time that all the values
are valid identifiers, which is a little bit of a bother -- being able
to _use_ identifiers in the first place would let us catch such errors
automatically and as _syntax_ errors.  Unfortunately, we can't do it
without counting, or having an alas very hypothetical construct to mean
"and all the rest goes here", as below.


>> > in combination with iterators).I'd also like to have the apply-* work
>> > in assignments, e.g. ``first, second, *rest = someList``. This would
>> > also make python's list destructuring facilities much more powerful.
>> 
>> Yes, I agree on this one.  Further, if the "*rest" was allowed to
>> receive _any remaining iterable_ (not just necessarily a list, but
>> rather often an iterator) you'd be able to use itertools.count()
>> and other unbounded-iterators on the RHS.
> 
> Indeed, as I noted in my previous post, iterators and such extensions
> would go very well together.

Now _that_ is a PEPworthy idea that might well garner reasonably vast
consensus here.  Of course, getting it past python-dev's another issue:-).


Alex





More information about the Python-list mailing list