Functions

In this notebook, we will discuss built-in and user-defined functions in Python, as shown under the following topics:
Built-in functions
Defining your own funcions
Multiple parameters
return vs. print
Variable Scope

Built-in Functions: input(), print(), int(), float(), str()

Python comes with several built-in capabilities. In this section, we will explore some useful built-in functions.

print()

The print() function is used to display characters on the screen. When we print something, notice that there is no output (no Out[] cell). This is because it does not return a value as an output (like a Python expression). It simply performs an action.

input()

The input() function is used to take input from the user. We specify the prompt we want the user to see within the parentheses. By default, input values are always of type string.

int()

The int() function is used to convert strings of digits to integers.

str()

The str() function is used to convert other data types to a string type and return it.

float()

The float() function is used to convert strings of digits that is a valid representation of a floating point number into floating point numbers.

age = input("Enter your age: ")
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/690836526.py in <module>
----> 1 age = input("Enter your age: ")

/usr/local/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
   1001         """
   1002         if not self._allow_stdin:
-> 1003             raise StdinNotImplementedError(
   1004                 "raw_input was called, but this frontend does not support input requests."
   1005             )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
age  # notice that it is a string
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/366431356.py in <module>
----> 1 age  # notice that it is a string

NameError: name 'age' is not defined
age = int(age)  # convert to int
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/3350126167.py in <module>
----> 1 age = int(age)  # convert to int

NameError: name 'age' is not defined
age 
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/2113650149.py in <module>
----> 1 age

NameError: name 'age' is not defined
radius = input("Enter radius value: ") # radius of circle
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/3719892012.py in <module>
----> 1 radius = input("Enter radius value: ") # radius of circle

/usr/local/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
   1001         """
   1002         if not self._allow_stdin:
-> 1003             raise StdinNotImplementedError(
   1004                 "raw_input was called, but this frontend does not support input requests."
   1005             )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
radius # currently a string
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/540134667.py in <module>
----> 1 radius # currently a string

NameError: name 'radius' is not defined

radius = float(input("Enter radius value: ")) # radius of circle can be a float
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/3717502585.py in <module>
----> 1 radius = float(input("Enter radius value: ")) # radius of circle can be a float

/usr/local/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
   1001         """
   1002         if not self._allow_stdin:
-> 1003             raise StdinNotImplementedError(
   1004                 "raw_input was called, but this frontend does not support input requests."
   1005             )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
radius  # now it is float
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/2386209522.py in <module>
----> 1 radius  # now it is float

NameError: name 'radius' is not defined
pi = 3.14159
print("Area of circle with radius", radius, "is", pi * (radius**2)) # comma adds space
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/3651269028.py in <module>
----> 1 print("Area of circle with radius", radius, "is", pi * (radius**2)) # comma adds space

NameError: name 'radius' is not defined
str(199)  # converts value to str type
'199'
str(None) # converts None to str type
'None'
dollars = 10
print('The burrito costs $' + str(dollars) + '.') # can also concatenate with + 
The burrito costs $10.

Question. Which of the functions among print(), input(), int*( return an explicit value as output?

What does the print() function return? print() doesn’t explicitly return anything and just displays the printed text on the screen.

It turns out that calling print() actually returns the special None value. Python uses a None return value to indicate the function was called to perform an action when there is no explicit return value.

To emphasize that calls to print() return None, try out the following piece of code:

str(print("Hello!"))
Hello!
'None'

Defining your own functions

Functions are a great way of abstracting and reusing useful blocks of code. We have already used built-in functions like print(), input() and int(). We can define our own functions as shown in the examples below.

def square(num):
    '''A simple user-defined function.'''
    return num * num

Calling or invoking the function: We can call a function many times, but we only define it once.

square(5)
25
square(7)
49

Parameters

A parameter names “holes” in the body of our function that will be filled in with the argument value for each invocation.

The particular name we use for a parameter is irrelevant, as long as we use the name consistently in the body.

def square(someNumber):
    return someNumber * someNumber

The following function call will generate the same result as the one from the definition of the function with a different parameter name.

square(5)
25

Function parameters only have meaning within the body of the function. We will come back to this concept, when we discuss variable scope.

someNumber  # what does this return?
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/3495249345.py in <module>
----> 1 someNumber  # what does this return?

NameError: name 'someNumber' is not defined

Multiple parameters

A function can take as many parameters as needed. They are listed one by one, separated by commas.

Important (Order matters!) The order of parameters specifies the order of argument values.

def totalSecs(mins, secs):
    '''Given the parameters mins and secs, return total number of seconds''' 
    return (mins * 60) + secs

If we call the function and provide the arguments in the wrong order (seconds first and then minutes), it will not work. The order of arguments in the function call should be the same as order of the corresponding paramenters in the function definition.

Call the function:

totalSecs(3, 67) # 3 minutes, 67 seconds
247

Why use docstrings? To help the user of the function understand the intended use.

help(totalSecs) # help is another in-built function!
Help on function totalSecs in module __main__:

totalSecs(mins, secs)
    Given the parameters mins and secs, return total number of seconds

Function calling Functions

Once you have defined a function, you can call it from within other functions.

def song(action):
    return "If you are happy and you know it, " + action
    
    
def singsong():
    print(song("clap your hands"))
    print(song("stomp your feet"))
    print(song("snap your fingers!"))
singsong() # what will happen?
If you are happy and you know it, clap your hands
If you are happy and you know it, stomp your feet
If you are happy and you know it, snap your fingers!

In the above example, singsong() is a zero-parameter function which is calling the function print(), which is calling the function song().

Note The function song() returns a string. The returned string replaces the function call within the print(), which results in it being printed.

Excercise: Write function average()

Let us define a function named average() that takes two numbers and returns the average of the two.

# Here define the function average
def average(x,y):
    return (x + y) / 2

Now try calling your function below:

average(6, 16)
11.0
average(5, 7)
6.0

return vs. print()

  • return specifies the result of the function invocation

  • print() causes characters to be displayed in the shell.

  • They are very different!

def exp(num, k):
    """Return the kth power of given number num"""
    return num**k

def printExp(num, k):
    """Print the kth power of given number num"""
    print("{} raised to exponent {} is {}".format(num, k, num**k))

Try out the result of the following expressions:

exp(3, 2) + exp(2, 3)
17
printExp(3, 2)
3 raised to exponent 2 is 9

Question. Will this work? What does printExp() return?

printExp(3, 1) + printExp(4, 2)
3 raised to exponent 1 is 3
4 raised to exponent 2 is 16
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/2939101779.py in <module>
----> 1 printExp(3, 1) + printExp(4, 2)

TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'
type(printExp(3, 2))
3 raised to exponent 2 is 9
NoneType
print(printExp(3, 2))
3 raised to exponent 2 is 9
None

Make Change Example

Problem. Suppose you are a cashier and you need to make change for a given number of cents using only quarters, dimes, nickels, and pennies.

Most cashiers use the following greedy strategy to make change using the fewest number of coins: use as many quarters as possible first, then as many dimes as possible next, and so on, using the fewest number of pennies last. Assume you have an unlimited supply of each coin.

# simple function to make change
def numCoins(cents):
  """Takes as input cents and returns the fewest number of coins of type
  quarter, dimes, nickels and pennies that can make change for cents"""
  pass 
  # we will write this together in class in Atom
help(numCoins)
Help on function numCoins in module __main__:

numCoins(cents)
    Takes as input cents and returns the fewest number of coins of type
    quarter, dimes, nickels and pennies that can make change for cents

Variable Scope

Local variables. An assignment to a variable within a function definition creates/changes a local variable. Local variables exist only within a function’s body, and cannot be referred outside of it. Parameters are also local variables that are assigned a value when the function is invoked.

def square(num):  
    return num * num
square(5)
25
num # num is not valid outside of square
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/var/folders/md/kwd9nc_d2ns0hw9wsvdrnt2c0000gn/T/ipykernel_42072/1831334593.py in <module>
----> 1 num # num is not valid outside of square

NameError: name 'num' is not defined
def myfunc (val):
    val = val + 1
    print('local val = ', val)
    return val 
val = 3
newVal = myfunc(val)
local val =  4
print('global val =', val)
global val = 3
newVal
4