Week 4: Functions
Lab 3 available now.
Today we’ll introduce another big, key computer science topic: functions. A function is a named sequence of statements that perform a particular operation. Some functions are built in (
int,str,float,input,print), but you can also define your own functions. Defining your own functions has many benefits:
make programs easier to read/understand
minimize programmer error
put repeated code into functions
hide low-level details of a function until you need to understand them.
In fact, you’ve been defining and using your own functions for a couple of weeks now, with the
main() function. This week, we’ll see many more examples of functions. You’ll see that functions can take input and return input, and even do other "side effects" in between.
Here is the syntax for how to define a function:
def <NAME>(<PARAMETERS>): <BODY>
<NAME> is the name of the function you define. The
<BODY> is a series of statements that you want to execute each time you use your function.
<PARAMETERS> is a list of zero or more inputs to the function. These parameters can be used inside the function just like any other variable.
Let’s look at some examples in
function_examples.py. We have defined four functions so far:
printIntro, printStarRow(n), starBox(n), and
main(). We will describe a few of these and then have you practice some.
Once a function is defined, you can call the function, by giving the name of the function and specific values for each parameter.
Exercise: practice function definition and calls
Practice defining and calling functions by modifying your program in
function_examples.py to implement
different values of
n. Try getting a value from the user with
main and passing the value to
What happens when a function gets called?
Python does a lot of behind-the-scenes work when a function gets called. Here is an outline of what happens:
Steps that occur when a function is called:
Suspend current function.
Evaluate arguments, copy them to parameters of the called function in order.
Execute called function using set values of parameters.
Return back to the calling function.
When calling a function, arguments are sometimes but not always plain values. Other times, they are complex expressions. These expressions get evaluated in Step 2 of the process above.
Often when you define a function, you want the function to return some
value back to whatever program called the function. You can do this
return command. For example, the built-in function
grabs a string of text from the user and returns it as a string. When
a return statement is reached, the function stops and immediately
returns the value indicated by the return statement.
For example, if you defined a function
def add(a,b) to add the values
b integers, you’ll probably want to define and return a variable
result=a+b. Then, once you’ve added the numbers, the
statement sends this value back to the calling function.
def add(a,b): """ Computes the sum of values a and b Returns result sample usage: ans = add(3, 4) print(ans) # Should print: 7 """ result = a + b return result
A stack diagram is a way to visualize what happens with variables in memory as Python executes your program. Consider the following program:
def square(number): toReturn = number*number return toReturn def main(): x = -9 squarex = square(x) print("%d squared equals %d" % (x, squarex)) main()
Now, on the whiteboard we’ll see how this computation happens in memory. The computer’s memory is where the program stores the state of a running program including the values of all variables and the stack of all functions currently waiting to finish. Here is the general procedure for how a function execute when called:
Pause the execution of the current function.
Create a stack frame for the called function.
allocate (place) parameters inside frame
allocate local variables for this function here
The value of each argument is copied to the corresponding parameter in order.
Execute called function step-by-step until the return.
Send back the return value to calling function.
Remove or pop the called function off stack.
Continue executing calling function that is now back on top of stack.
Some things to keep in mind as you draw your own stack diagrams:
Function call stack is on left, values belong on the right
The call stack always grows "up" when we call a function
The call stack shrinks when a function returns or reaches the end of its body without a return.
There is a separate box on the call stack for each function.
Parameters point to the same value as the inputs in the calling function.
The assignment operator changes the arrow.
A function can only access/reference variable names in its own stack frame. These variables are said to be in the function’s scope
Stack Example 2
def addNumbers(num1,num2): total = num1 + num2 print("In addNumbers:") print(num1) print(num2) print(total) #Show the stack diagram as it exists at this point return total def main(): x = 5 y = 9 ans = addNumbers(x,y) print("In main:") print(ans) print(total) #Gives an error. Why?
Answer the following questions:
What is the scope, respectively, of
Why does the last line of
main()give a runtime error?
Stack Example 3
Try another example of stack drawing.
def absval(x,y): if x > y: aval = x-y else: aval = y-x # draw stack to this point! # as it would look just before return... return aval def main(): a = 10 b = 35 result = absval(a,b) print("abs(%d-%d) = %d" % (a,b,result)) main()
totally.py, define a function
total(n), which takes a positive
integer as input and returns the sum of the first
integers. Then, call your function on several different inputs.
Strings, Slicing, and Mutability (oh my!)
We know of several string features so far. Assuming
s is a string variable:
len(s)to get the length of the string.
s + "more characters"to concatenate strings.
s * 3to repeat a string multiple times.
Strings can be compared with relational operators (e.g.,
s[i]to index into the string and access the ith character.
Python supports a more powerful indexing (
s) mechanism called slicing.
Slicing is a very useful shorthand notation for grabbing characters from a
string or items from a list. The syntax is similar to
range() where you can
have a start and a stop. Here are some examples:
>>> s = "ABCDEFGHIJKLMNOP" >>> s[2:5] 'CDE' >>> s[:6] 'ABCDEF' >>> s[6:] 'GHIJKLMNOP'
The first example above (
S[2:5]) grabs characters from positions 2, 3, and 4
(i.e., the start is 2, the stop is 5. Like
range() string slicing goes up to
but does not include the stop value.
The next two examples use implied defaults:
S[:6]is the same as
S[6:]is the same as
S[6:len(s)](grab from position 6 to the end).
first_half() function in
slicing.py that takes a string as input
and returns the first half of the string. For odd-length strings, it’s ok to
round down when determining "half".
You should test your function by writing a
main() function that prompts the
user for a string, passes that string to
first_half(), saves the function’s
return value into a variable, and then prints the result.
Advanced bonus exercise
Given a string representation of a strand of RNA, add a function to
slicing.py that prints 3-character groups from the strand. For example, given
strand = "ACUAUGACAUGCCAACGCUAGCGUCCU" ---
Can you print out this (i.e., the first three characters, then the next three, etc)?
0 ACU 3 AUG 6 ACA 9 UGC 12 CAA 15 CGC 18 UAG 21 CGU 24 CCU ---
range() function can take three arguments: a start, a stop, and
a step. The step determines how quickly
range() counts up. For example:
# Counts from 0 to 25 by 5. >>> for i in range(0, 26, 5): ... print(i) ... 0 5 10 15 20 25
While strings support indexing with brackets (
), Python does not allow you
to change the value in a position — the indices are read-only. For example:
>>> name = "Kevin" # Normal indexing works fine for reading characters. >>> name 'e' # Can't modify characters. >>> name = "a" Traceback (most recent call last): File "
", line 1, in TypeError: 'str' object does not support item assignment
Because strings allow reading but not writing, they’re said to be immutable. That is, their contents cannot be mutated (changed). Coming up soon, we’ll start to see data types that are mutable!