Structured programming Repeating actions and making decisions -------------------------------------- One of the common problems with all of the programs we've seen or written so far is that they always run straight through the end -- and then quit. They always do the same thing and they always just _stop_ after running through a pre-determined list of commands. Sure, they can be interactive -- they can ask you a question and they can use your answer in some way -- but there are two crucially important parts of programming which they're missing. They never _do an action over and over again_ and they never _make decisions_. Python has two kinds of statements which repeat actions -- "for loops" and "while loops". (A for loop repeats a group of statements once _for_ each element of a sequence type. A while loop repeats a group of statements _while_ some condition is met.) There are other ways of repeating actions, too; one is via a recursive function call (which we'll talk about later), and another is a somewhat exotic syntax called list comprehensions, which are basically a means of abbreviating for loops. List comprehensions are only available in newer versions of Python, and we may not talk about them at all, since they're never necessary for writing a program. (Similarly, we may not talk about "+=", which is also just an abbreviation of something else. Programming languages tend to implement some shorthands to let programmers write things more concisely, but you never _need_ to learn those abbreviations.) for loops --------- Here is an example of a for loop: for fruit in ["apple", "banana", "date", "fig", "grape", "kumquat"]: print fruit + "s are a kind of fruit" Another way of writing a similar loop: fruits = ["apple", "banana", "date", "fig", "grape", "kumquat"] for fruit in fruits: print "I like", fruit + "s" Here's an example of doing a more complex series of actions inside a loop. staff = ["Shari", "Katie", "Andrea", "Kevin", "Seth", "Marc", "Will", "Katina", "Henry", "Lee", "Robin", "Fred", "Cindy"] lengths = [] for person in staff: print "There is an EFF staff member named " + person + "." print "This person's name contains ", len(person), "letters." print "I'll remember that." lengths = lengths + [len(person)] print "There were", len(staff), "people." print "The longest name contains", max(lengths), "letters." print "The shortest name contains", min(lengths), "letters." #print "The average name contains", sum(lengths)/len(lengths), "letters." The last line of this example -- which I've commented out -- won't quite work unless you have defined a function called "sum" which can add up a bunch of numbers from a list. If you want to do that, put in the lines def sum(L): if L: return L[0] + sum(L[1:]) else: return 0 or alternatively def sum(L): total = 0 for x in L: total = total + x return i at the top of the program. (Don't worry about the "def" yet, though maybe you can see what it does.) Alas, remember that division of integers in Python yields an integer, so you might want to write float(sum(lengths))/len(lengths) instead of sum(lengths)/len(lengths), if you wanted to get a floating-point answer. Here is a program which uses a for loop inside another for loop to generate a bunch of addition facts. for x in range(1, 10): for y in range(1, 10): print x, "+", y, "=", x+y How is this different from for y in range(1, 10): for x in range(1, 10): print x, "+", y, "=", x+y A convenient thing about the range function and Python's list-element notation is that you can write things like for index in range(len(mylist)): print "Element at index", index, "of mylist is", mylist[index] to perform some action for each element of mylist, _and have access to the element's index_. while loops ----------- The while loop looks like: while condition: action and indicates that a particular action should be repeated over and over again as long as the condition is true. In human behavior, we could imagine while hungry(me): the_food = get_a_bite_of_food() chew(the_food) swallow(the_food) or while len(things_to_do) > 0: next_task = things_to_do[0] do(next_task) things_to_do = things_to_do[1:] or while not sleepy: talk_to_friends() if yawning(me): sleepy = 1 Anyway, these are good Python -- syntactically -- but they aren't necessarily concrete examples of programs you'd write. The second example, though, is a legitimate example of what we usually call queue processing -- successively performing a series of tasks in a list. We could also get much the same result by writing that as for task in things_to_do: do(task) things_to_do = [] but we can probably find cases in which the while loop is more useful (such as when there is a possibility that a certain task will fail). Conditions ---------- The "condition" which appears after the while statement can be many different things. Python has many comparison operators: a > b # "a is greater than b" (numerically, or sorting strings) a < b # "a is less than b" a >= b # "a is greater than or equal to b" a <= b # "a is less than or equal to b" a == b # "a is equal to b" (same notation as C) a != b # "a is not equal to b" (same notation as C) a <> b # "a is not equal to b" (same notation as BASIC) a is b # "a and b are the same object" (for object references, which # we haven't learned about yet; often, but not always, the # same as "a==b" a is not b # "a and b are not the same object" a in b # "a is an element of b" (if b is a sequence type like a list) a not in b # "a is not an element of b" There are other things you can test, too. Also, whenever a number is used as a condition, it's considered true if it's non-zero, and false if it's zero. Whenever a sequence type is used as a condition, it's considered true if its length is non-zero, and false if its length is zero (if it's empty). So if 0: is false, if "hello" is true, if ["good", "morning"] is true, and if [] is false. (In fact, the only things which are considered false are numbers which equal 0, and empty sequence types. There is a keyword "not" which you can think of as reversing the result of a condition, by making it true if it would have been false, or false if it would have been true.) A useful while example ---------------------- friends = [] done = 0 while not done: print "Please enter a friend's name." n = raw_input() friends = friends + [n] print "Do you have any more friends?" answer = raw_input() if answer in ["yes", "Yes", "Y", "y", "I do", "Yes.", "yes."]: done = 0 else: done = 1 print "You have", len(friends), "friends:", friends We could also get rid of the "not" and write this as friends = [] more_friends = 1 while more_friends: print "Please enter a friend's name." n = raw_input() friends = friends + [n] print "Do you have any more friends?" answer = raw_input() if answer in ["yes", "Yes", "Y", "y", "I do", "Yes.", "yes."]: more_friends = 1 else: more_friends = 0 print "You have", len(friends), "friends:", friends Each of these uses the "in" condition (to test whether the value of answer is an element of the list of possible "yes" replies"), as well as an if statement (explained below). Here's another way of writing it, which uses what looks like an infinite loop (which turns out to be not quite so infinite). friends = [] while 1: print "Please enter a friend's name." n = raw_input() friends = friends + [n] print "Do you have any more friends?" answer = raw_input() if answer not in ["yes", "Yes", "Y", "y", "I do", "Yes.", "yes."]: break print "You have", len(friends), "friends:", friends if statements ------------- Conditions are also useful in the if statement, which allows us to make decisions and perform or not perform an action based on the result of a condition (or "test"). if employer == "EFF": print "Your employer is cool!" Here is an extended example with several "if" statements. author = "Seth" lastname = "Schoen" print "Who are you?" user = raw_input() if len(user) < len(author): print "Your name is shorter than mine!" if len(user) > len(author): print "Your name is longer than mine!" if len(user) == len(author): print "Your name is just as long as mine!" if user == author: print "In fact, your name is the same as mine!" print "Maybe we are the same person!" print print "What's your last name?" user_last = raw_input() if user_last == lastname: print "Hey, wow! We're probably the same!" else: print "I guess you are some other", user else: print "It seems that we are different people, though." (You can try telling this program that you are Seth Schoen, Seth Greenstein, Seth Finkelstein, Fred, Lee, or Shari -- Seth Greenstein and Seth Finkelstein should elicit the same response here, but the other possibilities should give distinct responses from the program.) As you can see, an if statement can be paired with an else statement, which contains a block of statements which should be executed if the originally tested condition is false. To summarize: if condition: statements which will be executed if the condition is true go here, in this indented block (which can contain other if statements, for statements, or any other kind of statement) else: statements which will be executed if the condition is false (not true) go here, in this indented block There is also an "elif" statement, which you can use when you want to test a whole series of conditions. sf_statement = "You live in San Francisco." berkeley_statement = "You live in Berkeley." if name == "Seth": print "Hi, Seth!" print sf_statement elif name == "Michelle": print "Hi, Michelle!" print berkeley_statement elif name == "Lee": print "Hi, Lee!" print berkeley_statement else: print "You are somebody else." print "I don't know where you live." "elif" is short for "else if"; some feature like that exists in many programming languages. Let's make that a little shorter and show the use of the logical connective "or": if name == "Seth": print "Hi, Seth!" print sf_statement elif (name == "Michelle") or (name == "Lee"): print "Hi, " + name + "!" print berkeley_statement else: print "You are somebody else." print "I don't know where you live." I see an opportunity to make this slightly shorter again (with a very slight change in behavior): print "Hi, " + name + "!" if name == "Seth": print sf_statement elif (name == "Michelle") or (name == "Lee"): print berkeley_statement else: print "You are somebody else." print "I don't know where you live." With "for", "if", and "while", you can write very general and powerful programs! (Actually, you just need "if" and "while", or perhaps just "while" -- but all of them will be convenient, and "for" is useful since so many things which programs handle are represented as lists or other sequences.) Please see class-3-boolean.txt for more information about "and", "or", and "not". Block structure --------------- We say that Python has "syntatically significant indentation" (meaning that indentation or program spacing is actually significant to the meaning of a program). This is an unusual feature which is not shared with most programming languages! Many other languages use some sort of punctuation to show how statements are grouped together. For example, LISP uses parentheses, and C uses curly braces -- separating statements with semicolons. In Python, each statement is on a line by itself, and statements which are indented to a particular depth or distance from the left margin are considered to be grouped together into a "block". This guarantees that Python programs will be laid out visually in a way which is relatively easy to read -- related statements get grouped together physically. So it's easy to see exactly which statements are part of a loop, or which statements depend on a particular condition. Python blocks are nested inside of one another by further indentation, as in the example innermost = 0 print "Beginning program" for i in range(10): print "Beginning outer loop, with i=", i for j in range(5): print "Beginning inner loop, with i, j=", i, j for k in range(2): print "Beginning innermost loop, with", print "i, j, k=", i, j, k print "Ending innermost loop" innermost = innermost + 1 print "Ending inner loop" print "Ending outer loop" print "Ending program" print "Oh, wait: the innermost loop was executed", innermost, print "times." print "That's all!"