Function calls

  • A function is a named sequence of statements that performs a computation
  • To use a function, write a statement including a function call

In [1]:
type( 32 )


Out[1]:
int
  • The name of this function is type
  • It is built in to the Python language
  • The expression in the parenthesis is called the function's argument
  • The function returns the datatype of the argument, in this case an int, which is short for integer

Type conversion functions

  • Datatypes are very important in programming languages
  • A value's type dictates how it can be used
  • Python has functions that convert a value from one datatype to another
  • The two basic numeric datatypes are:
    • int For integer data
    • float For data with fractional parts expressed with a decimal point

In [2]:
# Convert an int to a float
float( 42 )


Out[2]:
42.0

In [3]:
# Convert a float to an int
int( 3.14159 )


Out[3]:
3
  • Note that converting from a float to an int can result in the loss of data
  • Numeric data is atomic
  • This means you can't split it up into different parts
  • However, string data is different

In [4]:
# Convert an int to a string
str( 42 )


Out[4]:
'42'

In [5]:
# Convert a float to a string
str( 3.14159 )


Out[5]:
'3.14159'
  • In these examples, numeric data has been converted to strings
  • The string '42' consists of two characters: 4 and 2
  • We read these characters as representing numbers, but the computer sees them as different
  • Note that the strings are indicated using single quotes ''
  • To use a string in a mathematical expression, it must be converted to a numeric datatype
  • If you don't, Python will halt execution and generate an error

In [6]:
int( '42' )


Out[6]:
42

Math functions

  • Beyond builtin functions, Python has a number of modules that provide additional functionality
  • Think of modules like a library of related functions and variables
  • Most of the important math functions can be found in the math module
  • Before you can use it, you need to import it into your code

In [7]:
import math
  • To access a function or variable defined in the module, you need to specify the name of the module and function using dot notation
  • Think of this as using an area code to dial a phone number
  • There could be multiple functions with the same name, but the module name tells Python where to find the one you want

In [8]:
radians = math.pi / 2
height = math.sin( radians )
  • You can find all the functions and variables in the module in the Python documentation https://docs.python.org/3/library/math.html
  • As an example, let's write code to calculate the circumference of a circle
    $c = 2 r \pi$

In [9]:
# Define the radius
radius = 3
# Calculate the circumference
circumference = 2 * radius * math.pi
print( circumference )


18.84955592153876

Composition

  • Building solutions to large problems using solutions to small problems as a building block is a fundamental skill in thinking like a computer science
  • The process of combining building blocks is called composition
  • Almost anywhere you can put a value in Python, you can put an expression
  • The exception is that only a variable can go on the left of an assignment statement

Adding new functions

  • You can create your own functions using a function definition

In [10]:
def print_star_wars_greeting():
    print( 'May the force be with you' )
    print( 'And also with you' )
  • def is a keyword that tells Python you are defininig a function
  • The name of the function immediately follows def
  • The naming rules for functions are the same as for variables
  • A verb is usually in a function name since it does something
  • For the moment, leave the parentheses empty
  • We will add parameters later
  • The header is the first line of the definition
  • The body is the rest of the function and is indicated by the :
  • Python uses the indentation to know where the body of the function starts and stops
  • The indentation is 4 spaces, not a TAB
  • Defining functions actually creates a variable with the name of the function and a value referred to as a function object
  • The function isn't executed until you call it in a _function call

In [11]:
print_star_wars_greeting()


May the force be with you
And also with you
  • Once you define a function, you can use it in later functions

In [12]:
def print_we_will():
    print( 'We will' )

def print_lyrics():
    print_we_will()
    print_we_will()
    print( 'Rock you' )

print_lyrics()


We will
We will
Rock you

Definitions and uses

  • Function definitions are executed like other statements, but they just create function objects
  • These store the statements in the body so they can be executed when the function is called
  • What happens if we try to call a function before it is defined?
    • Look back at the previous example
    • Move print_lyrics() to the top
    • Now, move print_we_will() in between the other two functions
  • What is it about Python that might cause this behavior?
  • You have to create a function before you can execute it

Flow of execution

  • The order in which statements are executed is called flow of execution
  • Execution starts at the top
  • Statements are executed one at a time
  • Think of a function as a detour to another part of code
  • When it is done, it comes right back to where it left
  • Don’t forget that functions can call other functions though

Parameters and arguments

  • Sometimes functions need additional information in order to execute properly
  • We have seen builtin functions using arguments
  • A good example was math.sin( radians )
  • You can do it with user-defined functions as well
  • Inside the function, arguments are referred to as parameters

In [13]:
def greet( name ):
    print( 'Hello', name )
    print( 'How are you doing?' )
greet( 'Boba Fett' )
robot = 'Vincent'
greet( robot )


Hello Boba Fett
How are you doing?
Hello Vincent
How are you doing?
  • In this example, name is the function's parameter
  • When the function is called the value of the parameter is set to the value of the argument
  • The name of the argument variable has nothing to do with the name of the parameter
  • In fact, you can call the function using an expression

In [14]:
greet( 2 * 'Yo ' + 'Ma' )


Hello Yo Yo Ma
How are you doing?

Variables and parameters are local

  • Variables created in a function are local to that function
  • This means that they only exist while that function is executing
  • They can't be accessed from outside the function and when the function ends, they are thrown away
  • For example, if we try to use the variable z outside of the function, Python will fail to compile the code and generate an error

In [15]:
def do_something( x, y ):
    z = x * y
    print( 'z=[' + str(z) + ']' )

do_something( 3, 4 )
# print( z ) # Fails since z doesn't exist


z=[12]
  • Note that parameters are local as well
  • x and y don't exist outside of the function

In [16]:
def do_something_else( x, y ):
    x = x + 2
    y = y - 1
    z = x * y
    print( 'Inside: x=[' + str( x ) + ']' )
    print( 'Inside: y=[' + str( y ) + ']' )
    print( 'Inside: z=[' + str(z) + ']' )

x = 3
y = 4
do_something_else( x, y )
print( 'Outside: x=[' + str( x ) + ']' )
print( 'Outside: y=[' + str( y ) + ']' )


Inside: x=[5]
Inside: y=[3]
Inside: z=[15]
Outside: x=[3]
Outside: y=[4]
  • Even if the variables share the same name, they are different variables
  • Think of this like telephone numbers and area codes. The same number can exist as a local number in different area codes.

Stack diagrams

  • TODO Insert an image
  • Sometimes it is useful to visualize the execution of a program using a stack diagram
  • Each function is represented by a frame
  • The frame holds all the important information about a function's execution, like the variables and the current line of execution
  • The currently executing function is placed on the bottom
  • Whenever you encounter a runtime error, Python will display an error detailing the current line of code and the function in which it resides
  • It will also list the line of code that called that function and the function in which it resides
  • This continues until it gets the main entry point of the program __main__
  • This is called a stack trace (or sometimes even a trace back)
  • To visualize the execution of the previous code that prints song lyrics, use this website http://www.pythontutor.com/visualize.html

Fruitful functions and void functions

  • We have already used functions that return a value
  • The book refers to these as fruitful functions
  • Other functions that don't return anything are called void functions
  • When a function returns something, it is rare that you want to ignore it
  • If you don't use the value, it is lost

In [17]:
def calculate_area_circle( radius ):
    return math.pi * radius ** 2

def calculate_area_donut( radius_outer, radius_inner ):
    area_outer = calculate_area_circle( radius_outer )
    area_inner = calculate_area_circle( radius_inner )
    return area_outer - area_inner


print( calculate_area_donut( 3, 2 ) )


15.707963267948966
  • If you try to save the return value of a void function, the variable will have a value of None
  • This isn't the same as the string 'None'

Why functions

There are a number of benefits of functions:

  • Creating a new function gives you an opportunity to name a group of statements, which makes your program easier to read and debug.
  • Functions can make a program smaller by eliminating repetitive code. Later, if you make a change, you only have to make it in one place.
  • Dividing a long program into functions allows you to debug the parts one at a time and then assemble them into a working whole.
  • Well-designed functions are often useful for many programs. Once you write and debug one, you can reuse it.

Debugging

  • Don’t use both tabs and spaces in your scripts/programs
  • Configure your editor to insert spaces when you hit the tab key
  • Don’t forget to save your script/program before you try to run it
  • It is frequently helpful to insert debugging statements in your code
  • Mine frequently look like the following

In [18]:
x = 55
print( 'x=[' + str( x ) + ']' )


x=[55]

Exercises

  • Write a function that takes a radius of a circle as an argument and returns (not prints) the circumference of the circle. Write a second function that also takes a raidus of a circle as an argument and returns the area of the circle. Calculate, by hand, the correct answers for circles with radii of 2, 3, and 4. Test the functions with these values and check for correctness.

In [19]:
def calc_circle_circumference( radius ):
    # INSERT YOUR CODE HERE
    return 0

def calc_circle_area( radius ):
    # INSERT YOUR CODE HERE
    return 0
  • Write a Python function that converts three (3) different Fahrenheit temperatures to Celsius temperatures. Create two versions of the function:
    1. Create a version that prints the converted temperature.
    2. Create a version that returns the converted temperature.

In [20]:
def convert_fahrenheit_to_celsius_print( f_temp ):
    # INSERT YOUR CODE HERE
    print( '0' )

def convert_fahrenheit_to_celsius_return( f_temp ):
    # INSERT YOUR CODE HERE
    return 0
  • Bob wants to know how much he should charge for his app on the App store. He ran two price trials (results below) to gauge interest. He also has some costs associated with selling his app (listed below). Write a function called calculate_profit that takes a proposed price for his app and returns the predicted profit earned. You may assume a simple linear relationship between the purchase price and the number of purchases.
Purchase price Number of purchases
\$2.00 1,000
\$3.00 700
Known costs
Refund rate 5\%
Transaction cost \$0.50

In [21]:
# Function to calculate the profit
def calculate_profit( app_price ):
    # ????

    # Profit!
    return 0