[Python-ideas] Generator syntax hooks?

Steven D'Aprano steve at pearwood.info
Thu Aug 10 09:42:33 EDT 2017


On Wed, Aug 09, 2017 at 01:23:28PM -0700, Chris Barker wrote:

> I can't recall the use case(s) at the moment, but I have definitely wanted
> a way to break out of a comprehension -- and not always with infinite
> iterators.
>
> After all, we have "break" in both for and while loops, so clearly there is
> the use case...

Indeed :-)


> If someone comes up with a clean and not confusing (and general purpose)
> syntax, I think it would be very useful.

We used to be able to (ab)use StopIteration to do this:

def Break():
    raise StopIteration

# generator expressions only, not list comprehensions
result = (expression for x in sequence if condition or Break())

but I believe that loophole has been closed in 3.6.


Comprehensions in Clojure have this feature:

http://clojuredocs.org/clojure_core/clojure.core/for

Clojure uses "when" where Python uses "if", giving:

;; :when continues through the collection even if some have the
;; condition evaluate to false, like filter
user=> (for [x (range 3 33 2) :when (prime? x)]
         x)
(3 5 7 11 13 17 19 23 29 31)

;; :while stops at the first collection element that evaluates to
;; false, like take-while
user=> (for [x (range 3 33 2) :while (prime? x)]
         x)
(3 5 7)


Translating into Python:

[x for x in range(3, 33, 2) if is_prime(x)]

[x for x in range(3, 33, 2) while is_prime(x)]  # hypothetical syntax

I don't think it is confusing. Regardless of the implementation, the 
meaning of:

[expression for x in sequence while condition]

should (I believe) be obvious to anyone who already groks comprehension 
syntax. The mapping to a for-loop is admittedly a tad more complex:

result = []
for x in sequence:
    if not condition: break
    result.append(expression)

but I'm yet to meet anyone who routinely and regularly reads 
comprehensions by converting them to for loops like that. And if they 
did, all they need do is mentally map "while condition" to "if not 
condition: break" and it should all Just Work™.



-- 
Steve


More information about the Python-ideas mailing list