[Tutor] Prime Numbers

spir denis.spir at gmail.com
Mon Dec 16 12:03:51 CET 2013


On 12/16/2013 09:49 AM, Rafael Knuth wrote:
> Hej there,
>
>>> number = 9
>>> for element in range(2,9):
>>> 3 % 2 != 0:
>>> My assumption is that the program should end the loop after the first
>>> iteration again and it then should return True.
>>
>> No. If it did that, it wouldn't be a *loop* at all, would it? The whole
>> reason loops (for and while) exist is to run the code repeatedly. If
>> they only ran once, no matter what, they would be useless.
>>
>> Unless you exit a loop early (with a return, a break, or by raising an
>> exception) the loop will jump back to the beginning until such time as
>> the loop is completed. Then it will jump to the code following the loop.
>>
>> So, here's a simple example:
>>
>> for element in range(5):
>>      print(element)
>>
>> With your assumption, you might think it will print 0, then stop. But
>> it doesn't. It prints 0, then 1, then 2, then 3, then 4. Each time
>> through the loop it jumps back to the beginning, gets the next value
>> from the range, and only when there are no more values to get does the
>> for-loop finish.
>
> That's actually a good example. Let me explain what I feel confused about.
> Print actually runs through the entire loop. But let's change the
> program like this:
>
> def RangeOfNumbers (n):
>      for i in range(n):
>          return i
>
> print(RangeOfNumbers(5))
>
> When you run this program, your result is:
>
>>>>
> 0
>
> So, return only returns the first value within the loop.
> If you want the loop run over the entire range of values, you have to
> change it like this:
>
> def RangeOfNumbers (n):
>      List = []
>      for i in range(n):
>          List.append(i)
>      return List
>
> print(RangeOfNumbers(5))
>
>>>>
> [0, 1, 2, 3, 4]
>
> Let's get back to my original program:
>
> def is_prime(number):
>      for element in range(2, number):
>          if number % element == 0:
>              return False
>      return True
>
> I was assuming that the for loop ends after the first round, just like
> in my first example above.
> But as you explained the for loop iterates through the entire range
> and only stops if a. there are no more values left to iterate through
> or b. the condition is met (return False if number % element == 0).
> That's the tiny little detail I am confused about: What does return
> exactly do? Does it return only the first value within a loop or does
> it iterate through all values within a loop? (unless a given condition
> is met)

You are confused about the way the loop machinary works behind the stage. It is 
actually rather simple. Imagine a construction like this:

while has_next():
     item = next_item()
     # use item, eg:
     print(item)
     # pass to next item, if any

A for-loop in python is equivalent (and translates) to something conceptually 
similar to the above piece of code. has_next() say whether there is at least one 
more item in the stream. If yes, then next_item() provides this item. When you 
use a for-loop on an "iterable" object, meaning a stream of items (a list, 
range, etc), then python behind the stage constructs and uses the equivalent of 
has_next and next_item() functions for the kind of stream you want to loop 
across, and traverses the stream using a construct equivalent to the while-loop 
above. [The reality is slightly different: instead of has_next, it uses an 
exception to know when we have reached the end of the stream; but the conceptual 
principle remains.]

If you know about linked lists, then the principle is very similar to traversing 
a list:

while cell:			# while (cell is not None)
     item = cell.value
     # use item
     cell = cell.next

If you want to dig into this even deeper. Here is an example of a class that 
would permit such traversal loop:

class ListStream:
     def __init__ (self, lst):
         self.lst = lst
         self.index = 0

     def has_next (self):
         return (self.index < len(self.lst))

     def next_item (self):
         item = self.lst[self.index]
         self.index += 1
         return item

Now, let us make a example list and its corresponding stream:

l = [1,3,5,7,9]
stream = ListStream(l)

Then, we can use the stream to traverse the list, for instance that way:

print("cubes:")
while stream.has_next():
     item = stream.next_item()
     print("    n:%d --> cube:%d" % (item, item*item*item))

Now, the stream has reached its end -- with index=5. To traverse the list again 
we could reset index=0 (or the stream class could provide a reset method), but 
in standard we would make a new stream. For all what we have done here by hand, 
python does an equivalent automagically behind the stage.

Denis


More information about the Tutor mailing list