We can now rewrite is_prime() to use the more sophisticated usage of range, and make is_prime() more readable:
def is_prime(n):
'''Return True iff n is prime
Arguments:
n -- a non-negative integer
'''
if n <= 1:
return False
if n == 2: #optional
return True
for i in range(2, n):
if n % i == 0:
return False
#Haven't returned False, which means we checked every possible i and haven't found a divisor
return True
Suppose that instead of the (correct) design above, we do something like this:
def is_prime_bad(n):
if n <= 1:
return False
if n == 2: #optional
return True
for i in range(2, n):
if n % i == 0:
return False
else:
return True
The difference is inside the for-loop: instead of only saying for n % i == 0: return False
we also added an else clause.
This would create a problem:
is_prime_bad(35)
The reason is_prime_bad() returns True (even though $35 = 5\times 7$, and so it isn't prime) is the else clause. We try every i between 2 and 34 (inclusive). When i is 2, 35 % i isn't 0, so we get to the return True statement. Once that return statement is executed, the function returns, and is_prime_bad(35) is evaluated to True.
That shouldn't happen: we should only return True after trying all the possible i's. Just because 35 isn't even (i.e., isn't divisible by 2), it doesn't mean it's prime. That's why the correct thing to do is to return True after the loop ends.
It is, however, okay to return False inside the loop. That's because if we found even one divisor of n, we know that n is definitely not prime, and it's okay to return from the function.
One small note: you always must put something in the if clause. The following produces an error:
if <cond>:
else:
<do something>
You can use pass in order to not do anything in the if clause, but not produce an error.
if <cond>:
pass
else:
<do something>
Here is an if-statement which is equivalent to what we have in is_prime():
if n % i != 0:
pass
else:
return False
(We can make it even close to the original statement by using not with ==:
if not (n % i == 0):
pass
else:
return False
If you find yourself writing something like that, you should obviously rewrite the code and write instead what we have in the original function:
if n % i == 0:
return False