Fixing the style of is_prime

We can now rewrite is_prime() to use the more sophisticated usage of range, and make is_prime() more readable:

In [1]:
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

More on designing loops: return inside for

Suppose that instead of the (correct) design above, we do something like this:

In [2]:
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:

In [3]:
is_prime_bad(35)
Out[3]:
True

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.

pass

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