Comp 112

Lecture 3

Calling and Defining Functions

2017.09.19

Calling Functions

Calling a function:

So functions generalize both statements and expressions.

We already met two functions last week:

type (<argument>)     #  returns the type of its argument to its caller

print (<argument>)    #  prints a textual representation of its argument to the screen

Input and Output Functions

Tip: if calling input causes a NameError then you’re using the wrong Python version.

Composing Functions

Coercion Functions

Python includes some basic coercion functions that convert values from one type to another.

These are named after the target type:

str (<expression>)      #  tries to convert the argument to a string

int (<expression>)      #  tries to convert the argument to an integer

float (<expression>)     #  tries to convert the argument to a float

bool (<expression>)     #  tries to convert the argument to a boolean

Implicit Coercion

What will the following do?

print (True * False)

Defining Functions

def my_fun (x , y) :                                                   #  the function header
    print ("i'll add " + str (x) + ' and ' + str (y) + ' for you...')  #  a statement in the function body
    return x + y                                                       #  a return statement in the function body

Function definitions have two parts:

A header consisting of:

A body consisting of:

Local Variables

def double (number) :              #  the parameter `number` is a local variable
    result  =  number + number     #  the variable `result` is also a local variable
    return result

Global Variables

Return Statements

None and NoneType

Returning vs Printing

It is important to understand the difference between returning and printing a value.

A value that is returned from a function is available for further use within the program.

It can be assigned to a variable, used in an expression, or passed as an argument to another function.

But a value that is printed to the screen is lost to the program: once printed, it is gone and can no longer be examined or manipulated.

In fact, print is a function that always returns None:

type (print ('hi'))
print ('hi') == None

Compare:

def double (n) :
    return n + n

def print_double (n) :
    print (n + n)
double (double (2))                 #  works fine
print_double (print_double (2))     #  doesn't work--why?

Functions and Effects

Function Call Execution

A function call creates a detour in the flow of program execution:

  1. The function arguments are evaluated.
  2. A new variable table is created, assigning the argument values to the function parameters.
  3. Control is passed to beginning of the function body.
  4. Control flows normally within the function body until a return statement is reached.†
  5. The argument to return is evaluated.‡
  6. The function’s variable table is abandoned.
  7. The return value is assigned to be the value of the function call.
  8. Control is returned to the function call site.

†) If no return is encountered, then “return None” is implied.

‡) If return has no argument, then “return None” is implied.

Call Graphs

def add_and_greet (x , y) :
    it  =  x + y
    greet_user ()
    return it

def greet_user () :
    it  =  print ('hi there!')

x  =  39
y  =  add_and_greet (1 + 2 , x)

Lets see what this program does by drawing its call graph.

Function Specifications

Dynamic languages like Python don’t keep track of these things, but you should using documentation string comments:

def quotient (x , y) :
    """
    signature:  int , int -> int
    precondition:  y != 0
    description:  returns the quotient of its arguments
    """
    return x // y

To Do This Week: