Ask Your Question

Revision history [back]

Your question is whether you can create local variables inside an expression (in particular, inside a list comprehension): Is there a Python equivalent of the Haskell 'let'? The answer is basically no, unless you acknowledge abominations like this:

w=[n for n in prime_range(5,10000) if (lambda m: (lambda k: (n+m+k).is_prime())(previous_prime(m)))(previous_prime(n))]

Let me turn your original list comprehension into a function:

def my_primes0(lower, upper):
    return [n for n in prime_range(lower,upper) if (n+previous_prime(n)+previous_prime(previous_prime(n))).is_prime()]

You create a list of primes in a range with prime_range, but subsequently you use previous_prime which does new superfluous primality tests. You can make better use of the list returned byprime_range like so:

def my_primes1(lower, upper):
    p = prime_range(lower, upper)
    for i in range(len(p)-2):
        if is_prime(p[i] + p[i+1] + p[i+2]):
            yield p[i+2]

This is a generator which you can use to create a list as follows:

sage: w1 = list(my_primes1(5, 10000))
sage: w1 == w
True

These are the timings on my machine (I increased the upper bound to get into the millisecond range):

sage: timeit('my_primes0(5,10000)', number=125, repeat=3)
125 loops, best of 3: 35.8 ms per loop
sage: timeit('list(my_primes1(5, 10000))', number=125, repeat=3)
125 loops, best of 3: 6.16 ms per loop

In general, if you want to use local variables in the definition of an iterator then you should probably define a generator (using yield).