[Python-ideas] Generator syntax hooks?
Nick Coghlan
ncoghlan at gmail.com
Thu Aug 10 00:11:48 EDT 2017
On 10 August 2017 at 00:54, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Yeah, if we ever did add something like this, I suspect a translation
> using takewhile would potentially be easier for at least some users to
> understand than the one to a break condition:
>
> {x for x in itertools.count(0) if 1000 <= x while x < 1000000}
>
> <=>
>
> x = set()
> for x in itertools.count(0):
> if 1000 <= x:
> set.add(x)
> # If you've never used the loop-and-a-half idiom, it's
> # not obvious why "while <expr>" means "if not <expr>: break"
> if not x < 1000000:
> break
>
> is roughly
>
> {x for x in itertools.takewhile(itertools.count(0), lambda x: x <
> 1000000) if 1000 <= x}
>
> <=>
>
> x = set()
> for x in takewhile(itertools.count(0), lambda x: x < 1000000):
> if 1000 <= x:
> set.add(x)
Ugh, this discrepancy is worse than I thought, since the translation
with that clause order is actually wrong (Terry mentioned this by
pointing out that the proposed syntactic translation implemented
"do...while" ordering). The takewhile example is also wrong, since it
has the arguments in the wrong order. Fixing both of those issues
gives the comparison:
{x for x in itertools.count(0) while x < 1000000 if 1000 <= x}
<=>
x = set()
for x in itertools.count(0):
# If you've never used the loop-and-a-half idiom, it's
# not obvious why "while <expr>" means "if <expr>: <loop body>
else: break"
if x < 1000000:
if 1000 <= x:
set.add(x)
else:
break
is roughly:
{x for x in itertools.takewhile(lambda x: x < 1000000,
itertools.count(0)) if 1000 <= x}
<=>
x = set()
for x in takewhile(lambda x: x < 1000000, itertools.count(0)):
if 1000 <= x:
set.add(x)
And I think that gets me back to pretty much where I was the last time
this came up: a while clause in comprehensions really only makes sense
in combination with a while clause on for loops, where:
for x in itertools.count(0) while x < 1000000:
...
was roughly equivalent to:
for x in itertools.count(0):
if x < 1000000:
...
else:
<loop else clause, if any, still runs here>
break
(such that there's only one loop from the point of view of
break/continue/else, but the loop may terminate based on either
exhaustion of the underlying iterator *or* some specific condition
becoming false)
While I do think such a clause would be more readable for more people
than the dropwhile/takewhile equivalents (especially when the latter
end up needing to use lambda expressions), I'm still dubious that
these cases come up often enough to justify the addition of a
for-while loop as a composite construct (the old "dropwhile and
takewhile aren't even common enough to justify being builtins, why
should they jump all the way to syntactic support?" question applies).
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
More information about the Python-ideas
mailing list