1

I've been doing some exercises, and having one question for you guys. following to the picture I added. for number =2 the range we get in the second line is from 2 until 2.

so, why dont i get some error message? How does it work?

How does the program know to skip it and return True?

Code:

def main(number):
    for i in range(2,int(number**0.5)+1):
        if number % i == 0:
            return False
    return True
print main(2)

Thanks!! code example

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    Not again... do **not** submit **pictures** of your code. Post the **actual code**. – Willem Van Onsem Oct 19 '17 at 17:57
  • To answer your question: because Python considers this an *empty* range. So it simply does not enumerate. Why do you want an error message? – Willem Van Onsem Oct 19 '17 at 17:58
  • OK, you are right about the code. I'd expect an error because I am talking about an I which does not exist. So what actually happens beyond the scene? What code lines do run? Thank you! – Almog Carmeli Oct 19 '17 at 18:04

1 Answers1

0

Some people think that Python attaches some special syntax between for and range, but range is an object that supports iteration.

This means that it has an __iter__ function that returns an iterator, and this supports the iterator protocol. This is a protocol that allows us to enumerate items out of that object. Like we can also enumerate over a list, tuple, set, etc.

for on the other hand simply uses this protocol such that for each iteration, it aims to fetch the next element out of the iterator. In case there is a next element, it assigns that element to the variable(s) on the left side. In case the iterator is exhausted (has no elements anymore), it stops.

In case you construct a range(start,stop) object where stop <= start. That range object is considered to be empty: it simply does not enumerate any items. for does not know what it is enumerating, but since the iterator over the range(..) element simply says that there are no elements anymore for stops.

You might indeed argue that it would be better if range(..) raises an error in case the stop is less than or equal to start. But usually it is wanted behavior that no error is risen, and the loop simply does not execute.

You can compare for i in range(0,n) to a construct in the Java/C++ language family:

for(int i = 0; i < n; i++) {
    //...
}

In this case if n is less than or equal to zero, the loop will not be executed either. The range(..) object somewhat a generator for such type of loops.

A extra note is that range actually is more sophisticated than described here in this answer, since you can also add a step, and you can countdown. But this has no impact on the semantics of this answer.

You can make the code more elegant, by using a generator in an all statement. Like:

def main(number):
    return all(number % i for i in range(2,int(number**0.5)+1))

Furthermore we can boost performance a bit, by only checking odd divisors (and 2):

def main(number):
    sq = int(number ** 0.5) + 1
    return (number & 1) and all(number % i for i in range(3, n, 2))
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555