statements in control structures (Re: Conditional Expressions don't solve the problem)

Andrew Dalke dalke at dalkescientific.com
Wed Oct 24 00:46:56 EDT 2001


Huaiyu Zhu wrote:
> there was recently a thread about prime
>algorithms.  I found that the clearest pseudocode would look like
>
>    def getprimes(x):
>        primes = []
>        for n in range(2, x):
>            for p in primes while p*p <= n:
>                if n % p == 0: break
>            else: primes.append(n)
>        return primes
>
>I have not been able to translate this into Python without using duplicate
>code or temporary variables - not sure about iterators as I haven't tried
>2.2 yet.

You may want to write more code in existing Python before
proposing new syntax forms  -- how many variations do you want?  :)

# I know, for some reason you don't like putting the end condition
# inside the loop.  But it's one I've brought up before and it's
# a simple mechanical transformation from what you want to do.
# And only one extra line (assuming your proposed code is written in
# a more readable form.)
def getprimes(x):
  primes = []
  for n in range(2, x):
    for p in primes:
      if p*p > n:
        primes.append(n)
        break
      elif n % p == 0:
        break
  return primes

# Here's one that's the same number of lines, although it
# makes a copy of the list while yours doesn't.  It's
# 13 extra characters.
def getprimes(x):
  primes = []
  for n in range(2, x):
    for p in filter(lambda p: p*p<= n, primes):
      if n % p == 0:
        break
    else:
       primes.append(n)
  return primes


# This may be slower, since 2/3 of the tests are
# removable in the first two tests, while this makes
# a copy of the primes.  On the other hand, it doesn't
# do the "p*p" test all the time.  But if you're worried
# about speed you wouldn't use this algorithm.
def getprimes(x):
  primes = []
  for n in range(2, x):
    pos = bisect.bisect(primes, math.sqrt(x))
    for p in primes[:pos]:
      if n % p == 0:
        break
    else:
      primes.append(n)
  return primes

# This starts returning answers quickly, instead of waiting
# for all the primes to be computed.  It also knows that 2
# is a prime so it skips all even numbers.
def getprimes(x):
  if x > 2:
    yield 2
  if x > 3:
    yield 3
  odd_primes = [3]
  for n in xrange(5, x, 2):
    for p in odd_primes:
      if p*p > n:
        odd_primes.append(n)
        yield n
        break
      elif n % p == 0:
        break

and can be used like

>>> for x in getprimes(sys.maxint):
...     if x % 10 == 7:
...             print x, "(ends in a 7!)"
...     else:
...             print x
...     if x > 30:
...             break
...
2
3
5
7 (ends in a 7!)
11
13
17 (ends in a 7!)
19
23
29
31
>>>

>This would also be handy for list comprehensions.  In analogy to
>
>    >>> a = range(10)
>    >>> [x for x in a if (x-5)**2 > 4]
>    [0, 1, 2, 8, 9]
>
>we could have
>
>    >>> a = range(10)
>    >>> [x for x in a while (x-5)**2 > 4]
>    [0, 1, 2]

Is that useful?  Not often enough I warrant.  BTW, you can do

def while_true(f, data):
  gen = iter(data)
  while 1:
    x = gen.next()
    if f(x):
      yield x
    else:
      break

>>> a = range(10)
>>> for x in while_true(lambda x: (x-5)**2 > 4), a):
...     print x
...
0
1
2
>>>

Or even without generators but with filter (so works with
any Python in the last decade.)

class while_true:
  def __init__(self, f):
    self.f = f
    self.flg = 1
  def __call__(self, x):
    if self.flg == 0:
        return 0
    if self.f(x):
        return 1
    self.flg = 0
    return 0

>>> a = range(10)
>>> filter(while_true(lambda x: (x-5)**2 > 4), a)
[0, 1, 2]
>>>

I'm betting it's more likely that Python will grow a new module
with various predicates or iterable functions than add new styles
of syntax.  Then you could do things like

  from generator_functions import lazy_filter, every_other

  for x in lazy_filter(lamba x: x%10==7, every_other(get_primes(100))):
    print x

and get the sequence starting 7, 47, 67, 97, 127, ...

I know I would like such a module - but not enough to write it.

>Thinking about this - perhaps the real problem is multiple exits for
loops -
>at least one normal end to loop and another abnormal end.

And I still insist there is no problem.  You've yet to really
come up with an example of how your proposal would clarify any
real code, and you have yet to show that the addition of a new
construct won't make Python more confusing.  Shortness does not
equal readable.

                    Andrew
                    dalke at dalkescientific.com
P.S.
  Who said "TMTOWTDI"?  :)






More information about the Python-list mailing list