我刚才遇到过这个(真正的)简单程序。它只输出第一个x素数。我很尴尬地问,有没有办法让它更“pythonic”,即凝聚它,使其(更多)可读?切换功能很好;我只对可读性感兴趣。
由于
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
答案 0 :(得分:7)
你的算法本身可能是以python的方式实现的,但以功能方式重写算法通常很有用 - 你可能最终会得到一个完全不同但更易读的解决方案(甚至更加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
答案 1 :(得分:6)
给定的代码效率不高。替代解决方案(同样效率低下):†
>>> 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
代替filter
。)
†:更有效的方法是使用Sieve of Eratosthenes。
答案 2 :(得分:5)
style guide中的一些小事。
n ==2:
=&gt; n == 2:
currentnumber
=&gt; current_number
答案 3 :(得分:2)
首先,您不应将max赋值给变量,因为它是用于从迭代中查找最大值的内置函数。此外,整个代码段可以写成
for i in xrange(3, int(sqrt(n))+1, 2):
if n%i==0: return False
此外,您可以直接执行
,而不是定义新的变量结果并将isprime返回的值放入其中。if isprime(currentnumber):
答案 4 :(得分:2)
我最近发现了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))
答案 5 :(得分:1)
通常你不会使用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 )
答案 6 :(得分:1)
你可以用筛子算法使其更加pythonic(所有素数小于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)
一个非常小的技巧会把它变成你的目标。
答案 7 :(得分:1)
翻译自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 :)),所以我将这个答案标记为社区维基。