代码之家  ›  专栏  ›  技术社区  ›  MercerKernel

这个可以做得更像蟒蛇吗?

  •  2
  • MercerKernel  · 技术社区  · 15 年前

    不久前我遇到了这个(非常)简单的程序。它只输出第一个x素数。我不好意思问,有没有办法让它更“蟒蛇式”的,即在使它(更)可读的同时浓缩它?切换函数很好;我只对可读性感兴趣。

    谢谢

    from math import sqrt
    
    
    def isprime(n):
      if n ==2:
        return True
      if n % 2 ==0 : # evens
        return False
    
      max = int(sqrt(n))+1 #only need to search up to sqrt n 
      i=3
      while i <= max: # range starts with 3 and for odd i
        if n % i == 0:
          return False
        i+=2
    
      return True
    
    
    
    reqprimes = int(input('how many primes: '))
    primessofar = 0
    currentnumber = 2
    while primessofar < reqprimes:
    
      result = isprime(currentnumber)
    
      if result:
         primessofar+=1
         print currentnumber
         #print '\n'
    
      currentnumber += 1
    
    8 回复  |  直到 15 年前
        1
  •  7
  •   Dario    15 年前

    您的算法本身可能是通过pythonical实现的,但是以功能性的方式重新编写算法通常是有用的——您最终可能会得到一个完全不同但可读性更高的解决方案(这甚至更像pythonic)。

    def primes(upper):
        n = 2; found = []
        while n < upper:
            # If a number is not divisble through all preceding primes, it's prime
            if all(n % div != 0 for div in found):
                yield n
                found.append( n )
            n += 1
    

    用途:

    for pr in primes(1000):
        print pr
    

    或者,考虑到Alasdair的评论,更有效的版本:

    from math import sqrt
    from itertools import takewhile
    
    def primes(upper):
        n = 2; foundPrimes = []
        while n < upper:
            sqrtN = int(sqrt(n))
            # If a number n is not divisble through all preceding primes up to sqrt(n), it's prime
            if all(n % div != 0 for div in takewhile(lambda div: div <= sqrtN, foundPrimes)):
                yield n
                foundPrimes.append(n)
            n += 1
    
        2
  •  6
  •   Stephan202 Alex Martelli    15 年前

    给定的代码不是很有效。替代解决方案(同样效率低下): γ

    >>> from math import sqrt
    >>> def is_prime(n):
    ...     return all(n % d for d in range(2, int(sqrt(n)) + 1))
    ... 
    >>> def primes_up_to(n):
    ...     return filter(is_prime, range(2, n))
    ... 
    >>> list(primes_up_to(20))
    [2, 3, 5, 7, 11, 13, 17, 19]
    

    此代码使用 all , range , int , math.sqrt ,请 filter list . 它与您的代码不完全相同,因为它打印素数 高达 一定的数字,不完全是 n 素数。为此,您可以:

    >>> from itertools import count, islice
    >>> def n_primes(n):
    ...     return islice(filter(is_prime, count(2)), n)
    ... 
    >>> list(n_primes(10))
    [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    

    它引入了另外两个功能,即 itertools.count itertools.islice . (最后一段代码只在python 3.x中有效;在python 2.x中,使用 itertools.ifilter 而不是 滤波器 )


    γ :更有效的方法是使用 Sieve of Eratosthenes .

        3
  •  5
  •   Mark Byers    15 年前

    一些小事情从 style guide .

  • 使用四个空格,而不是两个。(我个人更喜欢标签,但这不是蟒蛇的方式。)
  • 空行更少。
  • 一致的空白: n ==2: = & gt; n == 2:
  • 在变量名称中使用下划线: currentnumber = & gt; current_number
  •     4
  •  2
  •   Nikwin    15 年前

    首先,不应将max赋给变量,因为它是用于从iterable中查找最大值的内置函数。而且,整个代码段可以写成

    for i in xrange(3, int(sqrt(n))+1, 2):
        if n%i==0: return False
    

    此外,您可以直接执行以下操作,而不是定义新的变量结果并将isprime返回的值放入其中。

    if isprime(currentnumber):
    
        5
  •  2
  •   robince    15 年前

    我最近发现 Project Euler solutions in functional python 它有一些很好的例子,像这样处理素数。 Number 7 非常接近你的问题:

    def isprime(n):
        """Return True if n is a prime number"""
        if n < 3:
            return (n == 2)
        elif n % 2 == 0:
            return False
        elif any(((n % x) == 0) for x in xrange(3, int(sqrt(n))+1, 2)):
            return False
        return True
    
    def primes(start=2):
        """Generate prime numbers from 'start'"""
        return ifilter(isprime, count(start))
    
        6
  •  1
  •   poke    15 年前

    通常情况下,不使用while循环进行类似的简单操作。您宁愿创建一个范围对象并从中获取元素。因此,您可以将第一个循环重写为这个循环,例如:

    for i in range( 3, int( sqrt( n ) ) + 1, 2 ):
        if n % i == 0:
            return False
    

    如果你缓存你的质数,并且在检查一个新的质数时只检查以前的质数,那会更好。这样可以节省很多时间(并且可以很容易地用这种方法计算更大的素数)。这是我以前写的一些代码,可以使所有的素数达到 n 容易地:

    def primeNumbers ( end ):
        primes = []
        primes.append( 2 )
    
        for i in range( 3, end, 2 ):
            isPrime = True
    
            for j in primes:
                if i % j == 0:
                    isPrime = False
                    break
    
            if isPrime:
                primes.append( i )
    
        return primes
    
    print primeNumbers( 20 )
    
        7
  •  1
  •   badp    15 年前

    翻译自 stacktrace.it (特别是Daniele Varrazzo),这个版本利用了 a binary min-heap 要解决此问题:

    from heapq import heappush, heapreplace
    
    def yield_primes():
        """Endless prime number generator."""
    
        # Yield 2, so we don't have to handle the empty heap special case
        yield 2
    
        # Heap of (non-prime, prime factor) tuples.
        todel = [ (4, 2) ]
    
        n = 3
        while True:
            if todel[0][0] != n:
                # This number is not on the head of the heap: prime!
                yield n
                heappush(todel, (n*n, n))   # add to heap
    
            else:
                # Not prime: add to heap
                while todel[0][0] == n:
                    p = todel[0][1]
                    heapreplace(todel, (n+p, p))
                    # heapreplace pops the minimum value then pushes: 
                    # heap size is unchanged
    
            n += 1
    

    这个代码不是我的,我不完全理解( but the explaination is here :)),所以我将这个答案标记为社区wiki。

        8
  •  1
  •   Shinjikun    15 年前

    你可以用筛子算法使它更像蟒蛇(所有素数都小于100):

    def primes(n):
        sieved = set()
        for i in range(2, n):
            if not(i in sieved):
                for j in range(i + i, n, i):
                    sieved.add(j)
        return set(range(2, n)) - sieved
    
    print primes(100)
    

    一个很小的诀窍就能把它变成你的目标。