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 are valid representations of a floating point numbers into floating point numbers of type float.

age = input("Enter your age: ")
age  # notice that it is a string
age = int(age)  # convert to int
age 
radius = input("Enter radius value: ") # radius of circle
radius # currently a string

# radius of circle can be a float
radius = float(input("Enter radius value: ")) 
radius  # now it is float
pi = 3.14159
# comma adds space when printing
print("Area of circle with radius", radius, "is", pi * (radius**2)) 
str(199)  # converts value to str type
'199'
str(None) # converts None to str type
'None'
dollars = 10
# can also concatenate strings with + 
print('The burrito costs $' + str(dollars) + '.') 
The burrito costs $10.

Thought 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_87095/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 (for example, secs first and then mins), it will not work as intended. 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 is another in-built function that prints docstring!
help(totalSecs) 
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_87095/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!
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