patternpythonMajor
Simple twin prime finder
Viewed 0 times
primesimpletwinfinder
Problem
I'm really new to coding so I'm looking for a bit of feedback on this twin prime finder. She works pretty decent but I know it could be better.
import math
primes = []
def get_primes(lower, upper):
for num in range(lower, upper):
for i in range(2, num):
if num % i == 0:
break
else:
primes.append(num)
print get_primes(int(raw_input("Enter lower boundary")), int(raw_input("Enter upper boundary")))
print primes
for i in range(0, len(primes) - 1):
if primes[i+1] - primes[i] == 2:
print str(primes[i]), str(primes[i+1])Solution
Style
The Style Guide for Python Code called PEP 8 recommends a 4-space indent.
More functions
You could split your logic into smaller logical pieces which are easier to understand, to test and to optimise (I'll come back to this later).
For instance:
Avoid global
Your function
More functions (again)
You could add a function
It is practical (and conventional) in Python to use the
Now, the whole code looks like:
More beautiful loop
I highly recommend Ned Batchelder's excellent talk called "Loop Like A Native" (and any other talk he's done). You'll learn a lot about iterations in Python and that basically, anytime you write "range(len(list))", there is a better way.
In your case, you'll find various ways to iterate over consecutive items in a list like this:
(In Python 2, you could use
Then, this can easily be rewritten using a list comprehension:
More list comprehensions
You can also use list comprehensions in
Using builtins (and generator expressions)
Your function could be writen in a more concise way using the builtin
You can easily read this as "a number is prime is all divisions have a non-zero remainder".
It's exactly like the logic you had before but you are reusing already existing builtins and it teaches you new things :)
Now, the whole code looks like:
Optimisation
A simple yet very efficient optimisation when checking for prime is to use the fact that if a number is composite, for any pair of factors, one is less than or equal to the square root, and the other is greater than or equal to the square root, so you don't need to check the values larger than the square root of the number you are considering. There you can write something like:
Another optimisation you could do is to use the
The Style Guide for Python Code called PEP 8 recommends a 4-space indent.
More functions
You could split your logic into smaller logical pieces which are easier to understand, to test and to optimise (I'll come back to this later).
For instance:
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def get_primes(lower, upper):
for num in range(lower, upper):
if is_prime(num):
primes.append(num)Avoid global
Your function
get_primes would be much easier to use if instead of appending to a global variable, it was using a proper return value.def get_primes(lower, upper):
primes = []
for num in range(lower, upper):
if is_prime(num):
primes.append(num)
return primes
primes = get_primes(5, 56) # get_primes(500000, 560000)
print primesMore functions (again)
You could add a function
get_twin_primes to return ... the twin primes.if __name__ == "__main__":It is practical (and conventional) in Python to use the
if __name__ == "__main__": to separate your functions/classes definitions from the code actually using it. This makes code reuse possible via import : the functions/classes can be used by other modules without triggering all your computations.Now, the whole code looks like:
import math
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def get_primes(lower, upper):
primes = []
for num in range(lower, upper):
if is_prime(num):
primes.append(num)
return primes
def get_twin_primes(primes):
twins = []
for i in range(0, len(primes) - 1):
if primes[i+1] - primes[i] == 2:
twins.append((primes[i], primes[i+1]))
return twins
if __name__ == "__main__":
primes = get_primes(5, 56) # get_primes(500000, 560000)
print primes
for a, b in get_twin_primes(primes):
print a, bMore beautiful loop
I highly recommend Ned Batchelder's excellent talk called "Loop Like A Native" (and any other talk he's done). You'll learn a lot about iterations in Python and that basically, anytime you write "range(len(list))", there is a better way.
In your case, you'll find various ways to iterate over consecutive items in a list like this:
def get_twin_primes(primes):
twins = []
for p1, p2 in zip(primes, primes[1:]):
if p2 - p1 == 2:
twins.append((p1, p2))
return twins(In Python 2, you could use
itertools.izip instead of zip but if you're learning Python, you should try to use Python 3 directly).Then, this can easily be rewritten using a list comprehension:
def get_twin_primes(primes):
return [(p1, p2) for p1, p2 in zip(primes, primes[1:]) if p2 - p1 == 2]More list comprehensions
You can also use list comprehensions in
get_primes:def get_primes(lower, upper):
return [num for num in range(lower, upper) if is_prime(num)]Using builtins (and generator expressions)
Your function could be writen in a more concise way using the builtin
all.def is_prime(n):
return all(n % i != 0 for i in range(2, n))You can easily read this as "a number is prime is all divisions have a non-zero remainder".
It's exactly like the logic you had before but you are reusing already existing builtins and it teaches you new things :)
Now, the whole code looks like:
import math
def is_prime(n):
return all(n % i != 0 for i in range(2, n))
def get_primes(lower, upper):
return [num for num in range(lower, upper) if is_prime(num)]
def get_twin_primes(primes):
return [(p1, p2) for p1, p2 in zip(primes, primes[1:]) if p2 - p1 == 2]
if __name__ == "__main__":
primes = get_primes(5, 56) # get_primes(500000, 560000)
print primes
for a, b in get_twin_primes(primes):
print a, bOptimisation
A simple yet very efficient optimisation when checking for prime is to use the fact that if a number is composite, for any pair of factors, one is less than or equal to the square root, and the other is greater than or equal to the square root, so you don't need to check the values larger than the square root of the number you are considering. There you can write something like:
def is_prime(n):
"""Checks if a number is prime."""
if n < 2:
return False
return all(n % i for i in range(2, int(math.sqrt(n)) + 1))Another optimisation you could do is to use the
step argument of range in get_primes to iterate over odd numbers only (and add "2" at the beginning if needed).Code Snippets
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def get_primes(lower, upper):
for num in range(lower, upper):
if is_prime(num):
primes.append(num)def get_primes(lower, upper):
primes = []
for num in range(lower, upper):
if is_prime(num):
primes.append(num)
return primes
primes = get_primes(5, 56) # get_primes(500000, 560000)
print primesimport math
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def get_primes(lower, upper):
primes = []
for num in range(lower, upper):
if is_prime(num):
primes.append(num)
return primes
def get_twin_primes(primes):
twins = []
for i in range(0, len(primes) - 1):
if primes[i+1] - primes[i] == 2:
twins.append((primes[i], primes[i+1]))
return twins
if __name__ == "__main__":
primes = get_primes(5, 56) # get_primes(500000, 560000)
print primes
for a, b in get_twin_primes(primes):
print a, bdef get_twin_primes(primes):
twins = []
for p1, p2 in zip(primes, primes[1:]):
if p2 - p1 == 2:
twins.append((p1, p2))
return twinsdef get_twin_primes(primes):
return [(p1, p2) for p1, p2 in zip(primes, primes[1:]) if p2 - p1 == 2]Context
StackExchange Code Review Q#154694, answer score: 25
Revisions (0)
No revisions yet.