[Tutor] Two subsequent for loops in one function

Danny Yoo dyoo at hashcollision.org
Fri Nov 22 20:34:06 CET 2013


I agree with Peter Otten.  I want to try restating what he said to try to
emphasize what I think is the key point.


One basic skill that you learn as a programmer is how to handle nesting.
 One strategy is to give things names.  This can have benefits:

  1.  The name itself might make the code easier to read.
  2.  The thing being named might be simpler to understand in isolation to
the whole.


So when we look at the original program here here:

> for x in range(2, 10):
>     for y in range(2, x):
>         if x % y == 0:
>             print(x, "equals", y, "*", x//y)
>             break
>     else:
>         print(x, "is a prime number")

we can start to tease it apart, by giving names to sections of the program.
 Imagine a box or contour being drawn around the inner loop:


for x in range(2, 10):
    +------------------------------------------------------
     |    for y in range(2, x):
     |       if x % y == 0:
     |           print(x, "equals", y, "*", x//y)
     |           break
     |    else:
     |       print(x, "is a prime number")
     ------------------------------------------------------

We can give that thing a name!  We can do this naming with functions.
 Here's one approach: let's take that inner loop and make it into its own
function.

#################################
def InnerLoop(x):
    for y in range(2, x):
        if x % y == 0:
            print(x, "equals", y, "*", x//y)
            break
    else:
        print(x, "is a prime number")

for x in range(2, 10):
    InnerLoop(x)
#################################

This is fairly mechanical: see what variables are "free" in the body of the
thing we're pulling out and make them arguments to the function.  Here, the
inner loop depends on the value of x, so that's why it becomes an argument
in the function we've named "InnerLoop".


We can do this extract-and-name process again and again: good taste tells
us where we can take things too far and make the resulting code look silly.
 For example, we might do the same to the "x % y == 0" part of the inner
loop's computation.  This might look something like this:

#################################
def IsDivisibleBy(x, y):
    """Returns true if y divides evenly into x."""
    return x % y == 0

def InnerLoop(x):
    for y in range(2, x):
        if IsDivisibleBy(x, y):
            print(x, "equals", y, "*", x//y)
            break
    else:
        print(x, "is a prime number")

for x in range(2, 10):
    InnerLoop(x)
#################################

This might be taking naming too far.  Some people can see "x % y == 0" and
know that this is essentially a divisibility test.


But hopefully the point is clear: if some piece of code is complex, you
might be able to take a reductionist approach, pull it apart, and give
names so you can look at the loops in isolation, rather than all together.
 Reductionism doesn't always work in all contexts: sometimes we can chop up
the code so much that the result don't hold together.  Figuring out where
that balance is takes experience.  I'm still trying to learn the right
balance myself.  :P


Now, by the way, "InnerLoop" is an absolutely horrible name.  Can you take
a look at that function in isolation and describe what it is doing?  If so,
you can rename InnerLoop to something more appropriate.  That's what I
think Peter's point is in his naming of the inner loop to "unknown".  Don't
leave it named that way.  Once you figure out what it's doing, give it a
good name.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20131122/07e93896/attachment.html>


More information about the Tutor mailing list