CS 2120: Class #3¶

Functions¶
Probably the most important things in a programming language.
If you’re going to pay attention only once this term... now’s the time.
Script/program files are a nice way to organize many statements
- You eventually find yourself writing the same series of statements over and over
- (or cutting and pasting in your editor)
There’s gotta’ be a better way!
We want a way to group together sequence of statements that we frequently reuse
In Python, we do this with a function. Here’s one now:
def my_function(a_parameter): b = a_parameter * 2 print b
Once you’ve defined a function, you can call it from the Python interpreter in exactly the same way you’d call a built-in function like
print
.- So let’s use our function:
>>> my_function(2) 4 >>> my_function(7) 14 >>> my_function("Friends") FriendsFriends
When we call
my_function
, the Python interpreter executes the statements that make up the function, in order.Functions make code easy to reuse, and easy to read. More importantly they facilitate abstraction.
Quick Activity
Write your own function to do something with math.
Function Parameters¶
Note carefully the parameter (
a_parameter
) in the definition ofmy_function
. When you are defining a function, you want the function to be very general. You want it to work with any possible parameter that someone might want to give it.Imagine an
add_print(a,b)
function that adds two numbers and prints the result. You want it to add any two numbers, not just two specific numbers. A functionadd_print(3,5)
that can only add 3 to 5 wouldn’t be very useful. It would only ever print8
. So we introduce parameters.Parameters are like variables. When you call the function, the first thing that happens is the parameter values get set. Let’s go ahead and build our
add_print
function:def add_print(a,b): print a+b
Now that the function is defined, we can call it. Like this:
>>> add_print(5,2) 7
The call
add_print(5,2)
gets handled like this:- The interpreter checks to see if it knows about a function named
add_print
- We just defined
add_print
, so it does.
- We just defined
- The interpreter checks to see if it knows about a function named
When we defined it, we told the interpreter it should have two parameters:
a
andb
.The interpreter now takes the values in the call (in this case,
5
and2
) and assigns those values to the function parametersa
andb
.- In other words, the first thing the interpreter does in this case is set
a = 5
andb = 2
- In other words, the first thing the interpreter does in this case is set
Then the interpreter executes the body of the function, with the parameters having their new values.
What happens if we don’t give it enough, or too many parameters?
Abstraction: first steps¶
- Why is abstraction important?
Activity
Write down a “program” to make spaghetti (not in python, like on paper). You can only use the following statements:
locate [object]
grasp [limb]
release [limb]
move_limb_to [location]
wait [time in seconds]
Assume you start from a clean, empty, kitchen.
Activity
Write down a “program” to make spaghetti (not in python, like on paper). You can use plain English prose and assume you are addressing a human being.
You’ve now written programs at two levels of abstraction. Which was easier?
- Functions allow us to build towers of abstraction.
- A low level function might worry about how to set the individual pixels of the display to show the letter
A
. - Would you want to cut-and-paste that code every time you needed to print
A
? - Instead, we have a function called
print
that hides all those messy details from us. - We call
print
,print
calls other functions, which call other functions, which call other functions...
- A low level function might worry about how to set the individual pixels of the display to show the letter
Without organizing things into levels of abstraction writing complex software would be impossibly difficult.
Forget programming. In the rest of your scientific life, learning to think in terms of levels of abstraction is a hugely important skill.
- e.g., if you’re a Neuroscientist doing an fMRI experiment... should you be worrying about the state of a particular type of serotonergic receptor in a single neuron in the cortex?
Back to concrete things...¶
The general format for defining a function is:
def function_name(p1,p2,p3,p4, ... ): statement 1 statement 2 ... statement m
function_name
is... the name of the functionp1, p2
, etc. are called the parameters, you can have as many as you like- You tell Python which statements make up the body of the function by using indentation.
This is a somewhat unique feature of Python. Many other languages use pairs like
begin, end
,do, done
or{, }
to delimit the body of a function.Using whitespace might take some getting used to, but there is a huge benefit: your code “runs the way it looks”. If you’ve ever wasted time counting
}
s... you know what I mean.- However, white spaces can be uncomfortable too... sorry... deal with it...
Activity
Write a function catstr
which takes two strings as parameters and then prints out the concatenation of the
strings. e.g., if I call catstr('Hello ','world!')
it will print Hello world!
.
Activity
Now write a function crosscat
that will take four strings and print out the concatenation of the first and third string,
and then, on a new line, the concatenation of the second and fourth string.
BUT: your function isn’t allowed to use a print
statement! You can, however, use your catstr
function.
Execution Flow¶
The Python interpreter executes one statement at a time
To make sense of programs, we need to know which instruction gets executed when.
- In a program, the statements get executed in the order in which they appear in the program, top to bottom of the file.
- Later, we’ll learn how to jump around.
What happens when a function gets called? Let’s trace through this program:
def dostuff(a,b): c = b*2 d = (a+4)*2 c = d + c return c x = 2 y = 3 print dostuff(x,y) print "where am I?"
- So what happens is:
- The interperter makes a note of where the function is being called from.
- The flow of execution passes to the function
- The interpreter executes each statement in the function, in order.
- at the end of the function, control returns to the point from which the function was called.
Function values¶
Notice how
dostuff
ended with areturn
statement.The
return
statement tells Python: “return this value to whoever called this function”With
return
, functions evaluate into values.- Consider:
>>> print dostuff(2,2) 16 >>> print dostuff(4,4) 24 >>> print dostuff(2,2) + dostuff(4,4) 40
When the interpreter hits a
dostuff
, it goes and does stuff (executes the function).Because that function ends in a
return
, when execution flow comes back to the calling program, the call todostuff
gets replaced with whatever value gotreturn
ed.
Quick Activity
Write a function
nostuff(a,b)
which is identical todostuff(a,b)
except it does not contain areturn
statement.- What happens when you try this?
>>> print nostuff(2,2)
- What happens when you try this?
>>> print dostuff(2,2)
Activity
Write a function compmag(r,m)
to compute, and return, the magnitude of a complex number.
It should take the real component of the number as parameter r
and the imaginary component as m
.
Remember that | r + mi | = sqrt(r^2 + m^2). Say, does Python have a square root function? How would you find it?
Composition¶
Python functions can be composed just like mathematical functions.
We’ve already seen
print
composed withdostuff
- We can nest functions, too:
>>> dostuff(dostuff(2,2),dostuff(2,2)) 72
- If you get confused tracing nested functions, just remember:
- Functions get evaluted and turned into values
- Find a function you can evaluate
- Evaluate it
- Cross out the function and replace it with the value it returns
- Keep doing this until you’re down to one value.
Activity
Figure out the value of dostuff(dostuff(2,2), (dostuff(2,2) + dostuff(4,4)) )
using only pen and paper. No computers!
Activity
Figure out the value of nostuff(nostuff(2,2), (nostuff(2,2) + nostuff(4,4)) )
using only pen and paper. No computers!
Variable scope (not the mouthwash)¶
If you set a variable inside a function, it is local to that function.
No other function can see a function’s local variables. They are local. Consider this code:
def domore(a,b): c = 2*a + b return c
- What happens if I do this:
>>> print domore(4,4) 12 >>> print c NameError: name 'c' is not defined
Error! But
c
is defined indomore
! Why did we get an error?Moral of the story: variables have scope. This can actually be a suprisingly delicate concept and we’ll come back to it later.
Optional parameters for functions¶
Sometimes you want a function to have an optional parameter, with a pre-specified default value.
This is done very easily:
def my_function(a,b,c=3): do_stuff()
When you call
my_function(5,12)
,a
will have value5
,b
value12
andc
value3
.Because we specified a default value for
c
, we don’t have to provide one when we call the function.If we want to override the default though, we can:
my_function(4,3,2)
.A reasonable example:
def time_to_fall(d, a = 9.807): return math.sqrt(2*d/a)
Import¶
Another practical matter: sometimes you want to make a big library of functions. Maybe related to analysis data from your research.
You’d like to access some of those functions from another program that you’re writing.
- If you put your functions in a file called ‘myfuncs.py’, you can import them into another program like this:
>>> from myfuncs import *
(The
*
here means everything)- You could also use:
>>> import myfuncs
BUT, this adds a namespace. To access a function called
dostuff
in the filemyfunc
after this style ofimport
, you’d have to type:>>> myfuncs.dostuff(...)
Import — MORE¶
Can also import other people’s functions
>>> import math
>>> import numpy