How to utilize a loop of `for` and `else`?

So I tried the following code to also print out whether x is a prime or not, instead of just none and False. Why does it print only 4 is not a prime and not 2 is a prime?

def is_prime (x):
  if x < 2:
    return False
  else:
    for n in range (2, x-1):
      if x % n == 0:
        print x, "is not a prime"
        return False
      else:
        print x, "is a prime"
        return True
        
print is_prime (2)
print is_prime (4)

return means handing back a value to the function call, and indicating that the function is done/completed.

your function returns in the first iteration of the loop, so the return will break free from the loop (so to speak)

def is_prime (x):
if x < 2:
return False
else:
for n in range (2, x-1):
if x % n == 0:
print x, “is not a prime”
else:
print x, “is a prime”

is_prime (2)
is_prime (4)

But even like this it does not print 2 is a prime. And I am not returning True or False in between. I don’t understand how I can have it print 2 is a prime as well.

for x = 2 the loop will never run, there are no steps to take.

you solve two problems at once figuring out that a number is prime number after the loop ran all its iteration without the if condition being true, thus you get for else

Somewhere in the documentation it says that when,

for...
else...

is used, there should be a break in the for loop. No break, no else.

In a for - else loop, break causes else to be bypassed, so if you are searching for something and do not find it, you can print or return an appropriate notification. (The else clause also executes if the for loop is bypassed.):

for n in [3,7,9,10]:     # break is encountered
    if n % 2 == 0:
        print("{} is even".format(n))
        break
else:
    print("no even numbers")
# Output:
10 is even

vs

for n in [3,7,9]:     # break is not encountered
    if n % 2 == 0:
        print("{} is even".format(n))
        break
else:
    print("no even numbers")
# Output:
no even numbers

vs

for n in []:     # No break, but for loop never entered
    if n % 2 == 0:
        print("{} is even".format(n))        
else:
    print("no even numbers")

# Output:
no even numbers

Of course, if break is omitted, it won’t work like you want:

for n in [3,7,9, 10]:       # No break here
    if n % 2 == 0:
        print("{} is even".format(n))        
else:
    print("no even numbers")

# Output:
10 is even
no even numbers
2 Likes

def is_prime(x):

if x < 2:

    return False

else:

    for n in range(2, x-1):

        if x % n == 0:

            return False

return True

This is the solution provided. What I don’t understand here is that the final return is by the function itself. In this way, the returned value should always be True, regardless of what the else statement returns?

1 Like

no. Once a return keyword is reached, the function hands back data and is done executing. So when return false is reached, the function ends. It never reaches return True then

2 Likes

Why are we using x - 1 instead of just x?

assuming…x = 7

print range(2, x-1)
[2, 3, 4, 5] = 7/2, 7/3, 7/4, 7/5 all equal remainder thus prime

vs.

print range(2, x) = [2, 3, 4, 5, 6]
7/2, 7/3, 7/4, 7/5, 7/6 all equal remainder thus prime

I don’t understand why the extra logic of “-1” is required… am I missing something?

Cheers

1 Like

If x is 7, then range(x) is literally, [0, 1, .., x-2, x-1]. The author may have been describing it in literal terms. Go ahead and just use,

range(2, x)
1 Like

I don’t understand how below solution can generate True for x = 2. In the for loop, 2 % 2 = 0 and 2 % 1 = 0, response should be False. What am I not getting?

def is_prime(x):
  if x < 2:
    return False
  for i in range(2, x-1):
    if x % i == 0:
      return False
  return True 
  
print is_prime(2)

How does the code end up in the for loop? range() won’t produce any values given the stop value is equal to or smaller then the start value.

1 Like

To add to what @stetim94 said, you can add distinct print statements to your code to aid in following the flow of the program with different inputs:

def is_prime(x):
  print "Position 1"
  if x < 2:
    print "Position 2"
    return False
  print "Position 3"
  for i in range(2, x-1):
    print "Position 4"
    if x % i == 0:
      print "Position 5"
      return False
  print "Position 6"
  return True 
  
print "is_prime(2)\n", is_prime(2), "\n"
print "is_prime(-3)\n", is_prime(-3), "\n"
print "is_prime(6)\n", is_prime(6), "\n"
Output:

is_prime(2)
Position 1
Position 3
Position 6
True

is_prime(-3)
Position 1
Position 2
False

is_prime(6)
Position 1
Position 3
Position 4
Position 5
False

Alternatively, you could use a code visualizer like http://www.pythontutor.com/visualize.html#mode=edit or a debugging program.

Thanks. My apologies. I asked my question poorly. I understand the for loop steps but have question about the math. It seems to me that if we run the loop, 2 % 2 == 0. So shouldn’t that return False? Why is it returning True?

I thought covered this? The loop doesn’t run. So the math you think is happening, does never happen. The code doesn’t get there. So this is not related to math, this related to the loop and the flow of the program.

Will that line ever been seen if x is 2? Consider, what is,

range(2, 2)

?

Or as written above,

range(2, 1)

?
That’s the point @stetim94 is trying to make.

Okay! Thanks both! The range thing was tripping me up.

1 Like

@ midlindner the pythontutor link was very helpful. thanks.

1 Like

(2, x-1) was eating my brain. The author included it(2, x-1) into the solution and it is confusing… edit to the solution would be very much appreciated. It makes beginners confused whether “Codecademy” is wrong or user is wrong :confused::man_shrugging:!!!

This problem is many years old and will never be addressed. Likely the course will be put on a sunset path and get replaced with something else, or at least that has been the pattern over the years. From this side it’s likely nothing or very little is ever responded to with more than lip service. It is what it is. People are protecting their jobs and the boss pays the bills. There is never any money to go back over old course material and staff turnover is high so there is likely nobody around who had a hand in course creation, hence the sunset on old courses.

The real truth is that if the learners knew anything about prime numbers and prime factorization this would never be an issue. Sadly most learners don’t know these concepts and are expecting a CC course to magically turn them into geeks and gurus and math nerds. Ain’t gonna happen.

from math import sqrt
def is_prime(n):
    if n < 2: return False
    for x in range(2, int(sqrt(n)) + 1):
        if n % x == 0: return False
    return True

Now consider we have a list of prime numbers less than or equal to the square root of n. We no longer need the range at all. We could just use that list.

from math import sqrt
def is_prime(n):
    if n < 2: return False
    for x in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47][:int(sqrt(n)) + 1]:
        if n % x == 0: return False
    return True

That is enough tests to find all the primes less than 2500

So you see this course is not really messed up as much as many learners don’t understand Maths. They end up here in the forums, tin cup in hand and any answer we give them that works is enough to get them through the day.

2 Likes