Hi Mike,
You seem to be running Python 2. Is that intentional? Python 2 is now
unsupported and, if not completely obsolete, well on the way to being
obsolete.
Having said that, there’s a lot to be unpacked in your question. Let’s
start with the “divides” function:
def divides (n):
def div (k):
return n % k == 0
return div
This is sometimes called a “factory function”, because it builds a new
function each time you call it, and returns that new function as if it
were a value like 23 or “hello world”. If this seems weird to you, you
aren’t alone: it is a rather advanced technique that managers to confuse
beginners and experts alike, at least until they get used to it.
Personally I love factory functions, but I think this specific example
is a horribly confusing and convoluted way to test for prime numbers.
But it is what it is, and you have to live with it.
So let’s unpack the divides function carefully. If you call it with
input 7, for example, it returns a new function that expects a number k
as input and returns whether or not 7 remainder k is 0:
>>> func = divides(7)
>>> print(func)
<function divides.<locals>.div at 0x7f8bf1621b90>
>>> func(1)
True
>>> func(2)
False
>>> func(7)
True
If the remainder is 0, then k divides 7.
How do we use this to test whether 7 is prime?
- 1 always divides everything, so we can skip 1;
- if 2 divides 7, then 7 isn’t prime;
- if 3 divides 7, then 7 isn’t prime;
- if 4 divides 7, then 7 isn’t prime;
- if 5 divides 7, then 7 isn’t prime;
- if 6 divides 7, then 7 isn’t prime;
- and of course 7 divides 7, so we skip that.
Another way to do this would be to skip 1 and 7, and add up all the
“this divides 7” results. If the number of “this divides 7” results is
exactly 0 then 7 is prime; if the total is 1 or more, then 7 is not
prime.
(By the way, this is an inefficient way of checking for prime numbers,
but let’s not worry about efficiency now, let’s just get it working.)
So our first step might be to build a list of True/False “this divides
7” flags, and add them up:
div = divides(7)
total = sum([div(2), div(3), ... div(6)])
if total == 0:
# prime, so return True
else:
# not prime, so return False
This works because Python treats True as 1 and False as 0.
Clearly we don’t want to have to manually list all those individual
“this divides 7” tests, we want to use a loop. Except no loops are
allowed, so we have to use map.
div = divides(7)
flags = map(div, [2, 3, 4, 5, 6])
will give you a list of flags that you can then pass to sum to get the
total:
total = sum(flags)
So here is your exercise:
-
Put those steps into a function “prime(n)”.
-
Don’t hard code the value 7, but use the parameter n instead.
-
Likewise, don’t hard code the list [2, 3, 4, 5, 6]. Instead use the
function range to generate that list.
-
Once you have added up the total number of “this divides n” then you
can return either True or False as needed.
Remember that the True and False constants are different from the
strings “True” and “False”. There’s nothing special about the strings
“True” and “False” in Python, they’re just strings like “Hello”,
“Goodbye”, “wibble”, “qwerty” etc. The exercise here is to use the
special constants True and False, not the strings.
So once you have done all that, you should have a smallish function that
correctly returns whether or not it’s input is prime:
prime(2) # must return True
prime(3) # must return True
prime(4) # must return False
prime(100) # must return False
prime(101) # must return False
Try to get that much working on your own, then we can look at
squeezing the function down into just three lines.
Good luck, and feel free to ask questions if any of this is unclear.