Week 5: more functions, scope, stack diagrams
Announcements
-
Quiz 2 on Friday
-
Lab 4 due Saturday
-
lab 4 is functions and while loops, but we tell you exactly how to write the functions (what the params are, what it does, what it returns)
-
lab 5 will be more functions, but not as much guidance on each function
-
lab 7 will be yours to write (you design the functions and the whole program)
-
Monday
We started by looking at the countletter.py
program from last time:
def main():
phrase = "we love computer science"
letter = "e"
result = countletter(letter,phrase)
print("Number of %s's: %d" % (letter, result))
def countletter(ch,txt):
"""return number of ch in txt"""
count = 0
for char in txt:
if char == ch:
count += 1
return count
main()
Some questions students had from last time:
- how do letter
and phrase
get transfered to the countletter()
function?
- how does the result (the count
variable) get back to main()
?
- should I name the arguments the same as the parameters?
- can I use phrase
in the countletter()
function?
stack diagrams and scope
All good questions! And we’ll use stack diagrams to understand what’s going on and answer these questions.
Understanding stack diagrams helps you see how the computer works, and why python does what it does. It will also be very valuable in week 11 when we learn recursion (functions calling multiple copies of themselves).
A "stack" is just a data structure used by many programs. A stack is useful because it keeps track of where we are, and allows backtracking (e.g., hitting "undo" in your editor, or hitting the "back" button on your browser).
If you think of a stack of books or a stack of trays, you generally add items to the stack and remove items from the stack at the top end. This is different from a queue data structure (like a line at the bank or the grocery store) where items (people) are added at the back of the queue and removed (they checkout or are served) from the front of the queue.
So for your browser, say you visit espn.com, then swarthmore.edu, then cnn.com, and finally google.com. At this point, the broswer stack would look like this, with the current site on the top of the stack, and your history recorded in the rest of the stack:
google.com cnn.com swarthmore.edu espn.com
If you now hit the "back" button, the browser would "pop" the stack and remove the top item (google.com) and go to whatever is next on the stack (cnn.com).
As functions are executed in our program, they are placed on the top of the stack. When the function executing is done, it is removed from the top of the stack and the function below resumes execution. This is how the computer keeps track of the program flow.
For example, if you have a main()
function called first, and then
main()
calls another function, say func1()
, and before func1()
returns it calls another function, say func2()
, then at this point
"the stack" would look like this:
func2 func1 main
In addition to just showing what functions are on the stack, we will also include their variables and what data they refer to.
Here is a stack diagram for the countletter.py
program above,
where I have stopped at the end of the count()
function, just before
it returns to main()
:
In the above diagram, the "stack" is on the left, with two functions
currently on the stack, and the one on top is the function currently
executing (i.e., main()
has paused, and is waiting for countletter()
to finish and return).
In each stack frame, for each function, we list the variables that are active, with arrows that point to the data they refer to. This data, shown off to the right, is technically stored in a different area of the computer’s memory (this whole diagram is a simplified view of the memory of the computer, as the program is executing).
So main()
has just two variables: phrase
and letter
. The arrows
show what values are currently stored in these variables.
The countletter()
function has three variables: ch
, txt
, and
count
. Currently ch
points to the same data as letter
. This is
how arguments and parameters pass data from main()
to a function.
Also, txt
points to the same string as phrase
.
The count
variable initially stores a zero, but as the computer works
through the function, step by step, it is updated each time another "e"
is found in the txt
string. This is shown by the crossed-out values,
with the final value being 5. So at the end of the countletter
function, the value that will be returned back to main (count
) is 5.
So the rules for drawing the stack are as follows:
-
put the first function called (usually
main()
) on the stack -
inside the stack frame, show any variables that are assigned, with arrows pointing to their values (off to the right)
-
if another function is called, make a new stack frame for that function on top of the stack
-
again, inside that frame, show any parameters and local variables, with arrows pointing to their initial values
-
work through each function, step-by-step, updating any variables and their data
Usually, on quizzes, we will ask you to stop updating the stack diagram
before any functions finish and return. For completeness, if a function
did finish and return, we would remove it (and all it’s variables) from
the top of the stack. Any return value would usually be assigned back
to a variable in the calling function. For example, in the above
program, back in main()
, the result
variable would be assigned the
value 5, since count
is returned from the countletter()
function.
mutable objects in function
What about this program? Can you draw the stack for this one?
And what does the print(data)
line show, after the call to
bounds()
in main()
?
def main():
data = [2,37,300,127,-1]
print(data)
changed = bounds(data,0,255)
print(data)
print("Number changed: %d" % (changed))
def bounds(L,min,max):
"""check that all items in list are within min/max"""
numchanged = 0
for i in range(len(L)):
if L[i] < min:
L[i] = min
numchanged += 1
elif L[i] > max:
L[i] = max
numchanged += 1
# after loop, return how many were changed
return numchanged
main()
Wednesday
review function worksheet
Here’s the functionWorksheet.py
program that we started as a worksheet
on Monday. Can you predict the output of the whole program? Can you draw
the stack up to where function2()
is about to return?
# ------------------------------------------------------ #
def function1(L, X, S):
X = 100
L = list("WXYZ")
S = "pony"
# draw what stack looks like at this point, before function ends
# ------------------------------------------------------ #
def printline(ch):
print(50*ch)
# ------------------------------------------------------ #
def function2(L, X, S):
X = X + 1
L[0] = "hello"
L[2] = "goodbye"
L[4] = "lists are mutable!"
S = S + "pony"
# draw what stack looks like at this point, before function ends
# ------------------------------------------------------ #
def function3(mystring):
newstr = "**" + mystring + "**"
return newstr
# ------------------------------------------------------ #
def main():
L = list("ABCDE")
X = 42
S = "Swarthmore"
function1(L, X, S)
print("L: %s" % (L))
print("X: %d" % (X))
print("S: %s" % (S))
result = printline("!")
print(result)
printline("!")
function2(L, X, S)
print("L: %s" % (L))
print("X: %d" % (X))
print("S: %s" % (S))
printline("#")
S = function3(S)
print("S: %s" % (S))
# ------------------------------------------------------ #
main()
After you have studied the program, run it and make sure you understand the output!
Here are the main points from the above program:
-
in python, lists are mutable. This is why
function2()
is able to change some of the items inL
, and those changes are seen back inmain()
(when weprint(L)
) -
scope refers to where in a program a variable is active or accessible. Variables (and the data they reference) in one function are local (ie, not global) to that function. If you need the data from one function in another function, you should pass the data from function to function using arguments and parameters, or return the data from the called function back to the calling function
-
in python, a function returns
None
if you don’t explicitly return something (which is why you seeNone
from theprint(result)
line inmain()
start the mathquiz.py
program
Let’s write a program to present the user with a simple math quiz, testing their multiplication knowledge. Here’s a quick example:
$ python3 mathquiz.py Welcome to MathQuiz v0.1! What factor would you like to work on? 4 - - - - - - - - - - - - - - 4 x 6? 35 ....Nope. 4 x 6 = 24 - - - - - - - - - - - - - - 4 x 4? 16 ....Correct! - - - - - - - - - - - - - - 4 x 10? 40 ....Correct! - - - - - - - - - - - - - - 4 x 2? 8 ....Correct! - - - - - - - - - - - - - - You got 3 out of 4 correct. Good work!
Start with just these requirements:
-
ask for a factor
-
keep asking simple multiplication questions (factor times a random number from 1-12) until they get 3 in a row correct
If you have time: add a results(numprob, numcorrect)
function
that takes two arguments/parameters: the total number of problems
asked and the total number they got correct. This function should
output a status message based on the percent correct:
-
All correct: Super!
-
greater than 80% correct: Good work!
-
greater than 50% correct: Not bad…
-
less that 50% correct: Keep trying…
This function should also print the "You got X out of Y correct" message.
Friday
-
Quiz 2 for the first half of class
-
review
mathquiz.py
program (seejk_mathquiz.py
program) -
intro to objects: strings and lists
objects and methods
Both python strings and python lists are examples of objects. An object is just some data plus some methods (similar to functions) wrapped up together into one thing. We’ll learn more about objects as we go. For now we just want to learn the syntax of using them: object.method()
example
>>> course = "Introduction to Computer Science" >>> course.count("o") 4 >>> course.count("z") 0 >>> course.isalpha() False >>> course.upper() 'INTRODUCTION TO COMPUTER SCIENCE'
>>> grades = [88,90,78,99,93] >>> grades.sort() >>> print(grades) [78, 88, 90, 93, 99] >>> grades.append(75) >>> print(grades) [78, 88, 90, 93, 99, 75]
explanation/notes
The string methods used above are:
-
count()
— returns the number of occurrences of the given substring -
isalpha()
— returns True if all characters in the string are letters -
upper()
— returns an uppercase version of the string
There are many other str methods. In string objects, the data are the characters in the string.
The list methods used above are:
-
sort()
— sorts the list in place -
append()
— adds the given argument to the end of the list
In list objects, the data are the items in the list.
object.method()
syntax
Methods are always called with the dot syntax: object.method()
Again, methods are similar to functions, except they are tied to the type of object, and are called with this special syntax.
common string methods
Strings are objects in Python, and thus have methods that
we can invoke on them.
There are a lot of methods in the str
library for creating new
string objects from existing string objects and for testing properties
of strings. Keep in mind that strings are immutable!
Here are a few str
methods that may be particularly useful (run help(str)
in the python interpreter to see the full set):
str method | result | |
---|---|---|
upper() |
return copy of str converted to uppercase |
|
lower() |
return copy of str converted to lowercase |
|
isalpha() |
return True if string is all alphabetic characters |
|
isdigit() |
return True if string is all digits |
|
count(sub) |
return number of occurrences of sub |
|
index(sub) |
return index of first occurrence of sub |
|
strip() |
strip off leading and trailing whitespace |
|
split() |
split into list of "words" (see below) |
>>> S = "we LOVE cs" >>> S.upper() 'WE LOVE CS' >>> S.lower() 'we love cs' >>> S.isalpha() False >>> S.isdigit() False >>> S.count(" ") 2 >>> S.index("L") 3 >>> S.split() ['we', 'LOVE', 'cs'] >>> S = " we love cs " >>> len(S) 17 >>> S = S.strip() >>> len(S) 10 >>> print(S) we love cs
common list methods
Lists are also objects in Python, and thus have methods that
we can invoke on them. Here are a few that may be particularly useful
(run help(list)
in the python interpreter to see the full set):
list method | result | |
---|---|---|
append(item) |
add item to end of list |
|
insert(index,item) |
insert item at index |
|
extend(L1) |
add list L1 to original list |
|
sort() |
sort the list |
|
reverse() |
reverse the list |
|
count(item) |
return number of occurrences of item in list |
|
index(item) |
return index of first occurrence of item |
|
pop(index) |
remove and return item at index |
>>> L = list("ABCDEFG") >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G'] >>> L.append("X") >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'X'] >>> L.extend(["Y","Z"]) >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'X', 'Y', 'Z'] >>> L.reverse() >>> print(L) ['Z', 'Y', 'X', 'G', 'F', 'E', 'D', 'C', 'B', 'A'] >>> L.sort() >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'X', 'Y', 'Z'] >>> L.count("E") 1 >>> L.index("E") 4 >>> L.pop(4) 'E' >>> print(L) ['A', 'B', 'C', 'D', 'F', 'G', 'X', 'Y', 'Z'] >>> L.insert(1,"hello") >>> print(L) ['A', 'hello', 'B', 'C', 'D', 'F', 'G', 'X', 'Y', 'Z']
To see the full documentation for both the str
and list
classes:
$ python3 >>> help(str) >>> help(list)