Transcript Here

Review: Subroutines in Python
Subroutines (a.k.a. routines and procedures) are a way to break a program
up into named little pieces. If we do it right, these pieces work like building
blocks that can be reused. Using subroutines, we can solve a problem
once and then use that solution wherever we need it.
We have already been using subroutines that are provided by Python:
raw_input(), randint(), range(), etc. But as you know, we can
also make our own.
Here's a very simple subroutine definition:
def sayGoodbye():
print "Goodbye, my friend, goodbye. . . "
return
Then here's where we use it (If we want to be fancy, we say we call or invoke it):
. . .
if userResp == "no":
sayGoodbye()
. . .
Subroutine Parameters
You provide information to a subroutine by passing values to it. These
values are called parameters, or arguments. We’ve been doing this for a while:
numToGuess = random.randint(3,20)
userResp = raw_input(“Play again?”)
When you define a subroutine, you have to provide a list of any parameters that
it requires. In the subroutine say_goodbye() below, the parameter is mood:
def say_goodbye(mood):
if mood == "happy":
print "cheerio old chum!"
elif mood == "grumpy":
print "get lost, you bum"
else:
print "I don't know how to be", mood
return
# what will these do?
say_goodbye("grumpy")
say_goodbye("happy")
say_goodbye("perplexed")
One way to think about it. . .
• Think of the parameters as food
for the subroutine. You can
think of the parentheses as the
subroutine's mouth:
def feed_me(food):
print "me like", food
return
feed_me("krill")
feed_me("hamburgers")
More on Parameters
Subroutines can have multiple parameters:
def find_volume(length, width, height):
vol = length * width * height
print "the volume is", vol
return
When you define subroutine parameters, you're saying "Here
is the information that this subroutine needs to do its job",
and you're giving each piece of information a name so that
the subroutine can use it.
We say that the values for the parameters are passed to the
subroutine. The parameters are identified by their position
(or order) inside the parentheses when the subroutine is
called. For example, when this call is made:
find_volume(ln, 35, 2*num)
then inside the subroutine, length will have the value of the
variable ln, width will have the value 35, and height
will have a value 2 times the value of the variable num.
Make Sense?
def test(first, second):
# what will this print?
print first, second
return
first = "yo"
second = "pardner"
test(first, second)
# what will the line below print?
print first, second
What will be printed when we call main()?
Wait, there's more. . .
• Within a subroutine, the parameters act like variables that
get their initial values from whatever was passed in.
• But like a bubble popping, those variables disappear when
the subroutine returns. Ponder this:
def test(first, second):
# what will this print?
print first, second
first = "greetings"
second = "howdy"
return
first = "yo"
second = "pardner"
test(first, second)
# what will the line below print?
print first, second)
Two kinds of subroutines
A subroutine has a job – that is, it does something for us. There are two
kinds of subroutines:
1)
Some subroutines just do their job, and don’t give us back a value.
Examples:
turn_left()
circle(50, 50, radius)
2) Some subroutines do something, and give us back a value that we
can use later on in our program. We say that they return a value.
Subroutines that return values are frequently called functions.
Examples:
numsBy3List = range(1,100,3)
userResp = raw_input(“Play again?”)
numToGuess = random.randint(1,20)
print "There are", len(myList), "items"
Continuing the analogy. . .
If subroutines can eat, it stands to reason that they can
also, shall we say, poop*. That is, they can give you
something back after they've done their job. More
specifically, they can return a value.
def fahrenheitToC(fahrenheitTemp ):
retval = (fahrenheitTemp – 32) * 5 / 9.0
Means "return this value back to whoever called us"
return retval
>>> temp = fahrenheitToC(212)
Whatever fahrenheitToC() returned will become
the new value of temp
(We've already seen this kind of thing with
raw_input(), which poops a string that the
user typed, and range(), which poops a list
of integers.)
*Thanks to Kirby Urner for this illuminating metaphor!
# this subroutine makes an <h1> heading for
# the parameter text
def makeHtmlHeading(text):
return "<h1>" + text + "</h1>"
# this subroutine returns the larger of the
# two parameters
def max(val1, val2):
if val1 > val2:
return val1
else:
return val2
Some return
Examples
Using these subroutines:
>>> print makeHtmlHeading("Python Hates Me")
<h1>Python Hates Me</h1>
>>> print max(123,32)
123
# this subroutine returns the absolute
# value of the parameter
def abs(val):
if val > 0:
return val
else:
return –val
# subroutine returns a Boolean value:
# True if an odd number, otherwise False
def isOdd(val):
if val % 2 == 1:
return True
else:
return
return False
Using these subroutines:
>>> print abs(-17)
17
>>> print isOdd(17)
True
More
Examples
Returning Boolean Values
Subroutines can return Boolean values – True or False:
def startsWithVowel(word):
if word[0] in "aeiouAEIOU":
return True
else:
return False
If the subroutine returns True or False, it can be used in a condition for an if
or while statement:
userWord = raw_input("Gimme a word:")
if startsWithVowel(userWord):
print userWord + "starts with a vowel")
else:
print userWord + "does not start with a vowel"
We saw this kind of thing in RUR-PLE: front_is_clear(), on_beeper()
and the others are just subroutines that return True or False
Why return when you
can print?
• There is a big difference between a subroutine
printing a result and returning a result
• when a subroutine prints a result, it is displayed
to the human user, but that does not give the
code that called the subroutine access to the
value – the subroutine is a "black box" to the
rest of the program
• when a subroutine returns a result, that value is
available to whatever called it – to be saved in a
variable, used for further calculation, and so
forth
Some Harder Examples
# this subroutine returns the largest value in a
# list of numbers
def maxInList(numList):
maxVal= numList[0] # initial value has to be in the list
for nxt in numList:
if nxt > maxVal:
maxVal = nxt
return maxVal
# this subroutine returns a count of the number of times
# that the letter letter appears in the string word.
def count(word, letter):
numTimes = 0
for nxt in word:
if nxt == letter:
numTimes += 1
return numTimes
Using these subroutines:
>>> print max([1,44,932,34])
932
>>> print count("aardvark", "a")
3
Something Useful: readInt()
def readInt(prompt):
while True:
try:
ret = int(raw_input(prompt))
break
except:
print "Please enter an integer:"
return ret
Then your extra-credit #2 guessing game program
could be written:
low = readInt("Enter your low number:")
high = readInt("Enter your high number:")
and so forth. . .
See how parameters and return values make this work?
Something Useful: a Quadratic Formula
Solver
ax2 + bx + c = 0
import math
# pass in the values for the coefficients a, b, and c
# subroutine returns a list of the real roots,
# or an empty list if it has imaginary roots
def quadratic(a, b, c):
discriminant = (b ** 2) - (4 * a * c)
if discriminant < 0:
return [] # not ready for imaginary numbers!
else:
r1 = (-b + math.sqrt(discriminant))/(2.0 * a)
r2 = (-b - math.sqrt(discriminant))/(2.0 * a)
return [r1, r2]
Call stack
• Question: When a subroutine returns, where does it
return to? The subroutine doesn't know or care –
but the Python runtime has to know where to go
next.
• The address of the next line of code in the caller is
pushed onto the call stack before the subroutine is
called.
• If that subroutine then calls another subroutine, that
second return address is pushed on top of the
previous one.
• And so forth. . .
• When a subroutine returns, it returns to the address
on top of the stack. That address is popped off the
stack, exposing the one beneath it.
Recursion
# returns factorial of num
def factorial(num):
if num <= 1:
return 1
else:
return num * factorial(num – 1)
# what will this do?
def blowup():
return blowup()
File "<pyshell#2>", line 2, in blowup
blowup()
RuntimeError: maximum recursion depth exceeded