genexp surprise (wart?)

Ben Cartwright bencvt at gmail.com
Fri May 26 07:23:02 CEST 2006


Paul Rubin wrote:
> I tried to code the Sieve of Erastosthenes with generators:
>
>     def sieve_all(n = 100):
>         # yield all primes up to n
>         stream = iter(xrange(2, n))
>         while True:
>             p = stream.next()
>             yield p
>             # filter out all multiples of p from stream
>             stream = (q for q in stream if q%p != 0)
>
>     # print primes up to 100
>     print list(sieve_all(100))
>
> but it didn't work.  I had to replace
>
>             stream = (q for q in stream if q%p != 0)
>
> with
>
>         def s1(p):
>             return (q for q in stream if q%p != 0)
>         stream = s1(p)
>
> or alternatively
>
>         stream = (lambda p,stream: \
>                     (q for q in stream if q%p != 0)) (p, stream)


You do realize that you're creating a new level of generator nesting
with each iteration of the while loop, right?  You will quickly hit the
maximum recursion limit.  Try generating the first 1000 primes.


> I had thought that genexps worked like that automatically, i.e. the
> stuff inside the genexp was in its own scope.  If it's not real
> obvious what's happening instead, that's a sign that the current
> behavior is a wart.  (The problem is that p in my first genexp comes
> from the outer scope, and changes as the sieve iterates through the
> stream)


I don't see how it's a wart.  p is accessed (i.e., not set) by the
genexp.  Consistent with the function scoping rules in...
http://www.python.org/doc/faq/programming/#what-are-the-rules-for-local-and-global-variables-in-python
...Python treats p in the genexp as a non-local variable.

--Ben




More information about the Python-list mailing list