[Python-Dev] generator expression syntax (original) (raw)
Gareth McCaughan gmccaughan at synaptics-uk.com
Wed Mar 24 04:37:45 EST 2004
- Previous message: [Python-Dev] generator expression syntax
- Next message: [Python-Dev] generator expression syntax
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Wednesday 2004-03-24 05:46, Robert Mollitor wrote:
The idea of generator expressions seems good, but the proposed syntax seems a little wrong to me.
First, the syntax is too dependent on the parentheses. To my mind, this is a fourth meaning for parentheses. (1) Parentheses group and associate expressions: "(a * (b + c))", "if (a and b)". (2) Parentheses construct tuples: "(1, 2, 3)", "()", "('a',)". (3) Parentheses enclose argument lists (arguably a special case of tuple-constructor): "def f(a, b, c)", "obj.dump()", "class C (A, B)". And now (4*) generator expressions: "(x*x for x in list)". I realize that in some sense the parentheses are not part of the expression syntax (since we wouldn't require "sum((x * x for x in list))"), but they are mandatory nonetheless because you can't have "a = x*x for x in list". This seems like it stretching a familiar construct too far.
Actually 4 and 2 are very similar. It's commas that construct tuples, not parentheses; the parentheses are just necessary in some contexts to shield the tuple construction from other things going on nearby. Requiring parens around a generator expression is just like requiring parens around a single-element tuple expression.
Second, it looks like a "tuple comprehension". The list comprehension construct yields a list. A generator expression looks like it should yield a tuple, but it doesn't.
OK, so generator expressions should be wrapped in the same punctuation that's used to write explicit generators. Er, except that there isn't any.
Third, it seems Lisp-ish or Objective-C-ish and not Pythonic to me. I realize that is just a style thing, but that's the flavor I get.
There are two separate statements here: (1) it seems Lisp-ish or ObjC-ish, and (2) it doesn't seem Pythonic. #1 isn't a problem in itself; are you deducing #2 from #1 or claiming that it's true in its own right? (I don't see either #1 or #2 myself, but I find #1 easier to sympathize with than #2.)
Fourth, it seems like this variable binding thing will trip people up because it is not obvious that a function is being defined. Lambdas have variable binding issues, but that is obviously a special construct.
It's not clear to me that lambdas are any more obviously a special construct than generator expressions. Are you sure it's not just that you're used to lambdas and know that they're special, but aren't yet used to generator expressions?
OK, I not completely sure if this will work to everyone's satisfaction, but here is my proposal: replace the
(x*x for x in a) construct with lambda: yield x*x for x in a
I predict that to a good first approximation this one won't work to anyone's satisfaction.
CONS - "Ick, lambdas" - It's longer
- lambda doesn't mean "generator expression" or "thing involving variable binding" or anything like it; it means "anonymous function"
- it introduces a magical new thing that you can do only in lambdas and not in named functions
- The feature of ordinary generators that this trades on (namely that a generator definition makes something that you call in order to get an iterable thing) is probably the single most obscure point about generators
- the variable binding features that lambdas already have aren't the same ones that are being proposed for generator expressions
- it's as ugly as, ummm, something very ugly
PROS
- Lambdas are funky, but they are explicitly funky: look up 'lambda' in the index and go to that section of the book
This "pro" would equally justify overloading "if" or inventing a keyword "wombiquangle" for this purpose.
- Use the variable binding rules of lambas and people will be as happy with that as they are with lambdas in the first place (for better or worse)
The use cases of lambdas and of generator expressions are not the same. Why should the appropriate variable binding rules be the same? And why, therefore, should people be equally happy with them?
So here would be the recasting of some of examples in PEP 289:
sum(lambda: yield x*x for x in range(10)) d = dict (lambda: yield x, func(k) for k in keylist) [etc]
I can't believe you typed all those in and looked at them and still like this idea :-).
# I think the following would work, too for xx in lambda: yield x*x for x in range(10): print xx
# If so, how's this for decadent for i,a in lambda: yield i,list[i] for i in range(len(list)): print i, a
You think this is a good thing? Compare these, with their misleading initial segments "for something in lambda:" and all, with
for xx in (x*x for x in range(10)):
print x
for i,a in ((i,list[i]) for i in range(len(list))):
print i,a
which, for all their allegedly superfluous parentheses and allegedly weird variable binding behaviour, I can at least read.
-- g
- Previous message: [Python-Dev] generator expression syntax
- Next message: [Python-Dev] generator expression syntax
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]