Functions#

Often in programming you want to do the same task again and again. Instead of repeatedly typing the same code or copy and pasting it, you can save the code in a reusable function.

A function is a set of Python instructions or statements that can be executed later. If you’re familiar with macros in spreadsheet programs, it’s kind of like that.

Table of Contents

Part 1: Defining and calling#

../_images/playing-piano.jpg

When you create or define a function, you can imagine it’s like a music roll for a self-playing piano.

Later when you want to use or “play” it, you call the function.

Function syntax:

To define a function you’ll write a compound statement that starts with the def keyword. Next choose a name or identifier that will be used to call it, followed immediately by a pair of parenthesis and a colon.

On a new, indented line, add the statements that make up what the function does. Each of the statements indented at the same level will be part of the function.

def NAME(PARAMS):
    BODY

NAME

name of the function

PARAMS

zero or more comma separated names for variable arguments

BODY

statements to execute each time the function is called

Here’s a simple example.

def hello():
    print("Hello.")

To call a function add a pair of parenthesis immediately after the function name. For example, here’s how to call the hello function.

hello()
Hello.

Part 1.1: Exercise#

Exercise 6 (horizontal line function)

Write a function called hr to print a line of dashes 100 characters wide, like so:

--------------------------------------------------

Part 2: Parameters and Arguments#

While it is useful to be able to repeat exactly the same lines of code, often we want to repeat tasks that are almost the same. This is where parameters and arguments come in, because they let us change the value of specific variables when a function is called.

Part 2.1: Parameters and Arguments#

A parameter is a variable name you give to data that the function gets later. You add it to the function definition as you’ll see below.

The actual values, called arguments, get sent to the function and assigned when the function is called, then cease to exist when the function is done being executed.

To define a function with a parameter, put the parameter (variable) name you picked inside the parenthesis on the def line.

def hello(name):
    message = "Hello " + name + "."
    print(message)

Similarly, put the argument, (the variable value) inside the parenthesis when calling the function.

hello("John")
Hello John.

When the function is executed the argument value is assigned to a variable with the parameter name you chose. As if each time you call the function, the line PARAM = ARG is run first.

So that this:

def hello(name):
    message = "Hello " + name + "."
    print(message)

hello("Mary")

Is equivalent to:

name = "Mary"
message = "Hello " + name + "."
print(message)

Separate multiple parameters with a comma.

def greet(time, name):
  message = "Good " + time + " " + name + "."
  print(message)

The same with multiple arguments.

greet("morning", "Mr. Smith")
greet("afternoon", "Mrs. Doe")
Good morning Mr. Smith.
Good afternoon Mrs. Doe.

Part 2.2: Exercise#

Exercise 7 (header function)

Write a header() function that takes one string parameter title and prints the title followed by a line of dashes the same length of the title, like so:

>>> header("Chapter One")
Chapter One
-----------

Part 2.3: Positional Arguments#

Most of the time functions are called using positional arguments. That is, each argument is assigned based on its position in the argument list.

Lets look at the following function as an example.

def winners(first, second, third):
  """Print the contest winners"""
  print(f"The first place winner is: {first}")
  print(f"The second place winner is: {second}")
  print(f"The third place winner is: {third}")

When we call it below, "Alex" is assigned to the variable first because that argument is the first one passed; "Bob" is assigned to second because that argument is the second passed, and so on.

winners(
  "Alex",
  "Bob",
  "Celeste",
)
The first place winner is: Alex
The second place winner is: Bob
The third place winner is: Celeste

When calling functions this way, changing the order of the arguments will change the parameters they are assigned to.

winners(
  "Celeste",
  "Alex",
  "Bob"
)
The first place winner is: Celeste
The second place winner is: Alex
The third place winner is: Bob

Part 2.4: Keyword Arguments#

You can also use keyword arguments when calling a function to make it clear which argument is which. Just put the parameter name followed by an = in front of the argument value.

winners(
  first="Alex",
  second="Bob",
  third="Celeste"
)
The first place winner is: Alex
The second place winner is: Bob
The third place winner is: Celeste

You can even mix and match positional arguments and keyword arguments, as long as you put all of the positional arguments first.

winners(
  "Alex",
  second="Bob",
  third="Celeste"
)
The first place winner is: Alex
The second place winner is: Bob
The third place winner is: Celeste

When using keyword arguments, you can change the order of your arguments without effecting how they are assigned.

winners(
  second="Bob",
  first="Alex",
  third="Celeste"
)
The first place winner is: Alex
The second place winner is: Bob
The third place winner is: Celeste

It can also be useful to use keyword arguments to make your code more clear. For example, imagine a calculate_cost function that takes a bunch of numeric arguments.

def calculate_cost(price, quantity, tax, tip):
  ...

Which of the following lines of code do you think is easier to understand?

cost = calculate_cost(
  4.75,
  30,
  0.08,
  0.2,
)
cost = calculate_cost(
  price=4.75,
  quantity=30,
  tax=0.08,
  tip=0.2,
)

Some functions have default values for arguments, making them optional. When there are multiple arguments with default values, you can use keyword arguments to pass some arguments while skipping others.

For example, the print() function can take the optional keyword arguments end, for what string to append to the end of the text (default "\n"), and sep, for what string to put between each argument when printed (default: " ").

You can use keyword arguments to specify either or both.

# called normally without keyword arguments
print("hello")
print("there")
hello
there
# passing the `end` keyword argument
print("hello", end=" ")
print("there", end=".")
hello there.
# called normally without keyword arguments
print("555", "555", "5555")
555 555 5555
# passing the `sep` keyword argument
print("555", "555", "5555", sep="-")
555-555-5555

Part 2.5: Exercises#

Exercise 8 (keyword arguments)

  1. Call the print() function with the arguments "a", "b", and "c" with a value of "\n" for the sep keyword argument.

  2. Call the print() function multiple times in a row, with the value of "... " for the end keyword argument.

  3. a. Write a function called birthday that takes the arguments name, month, day and year, and prints "____s birthday is on ___ __, ____."

    For example: “Homer Simpsons birthday is on May 12, 1956.”

    b. Call it with multiple names and birthdays, using positional arguments and keyword arguments.

Part 3: Returning values#

The return statement is used to exit a function and optionally send data back to the caller.

By itself return works similar to the break statement in a for loop. No other code in the function will be executed.

def print_stuff():
  print("this will be printed")
  return
  print("this will never be printed")

print_stuff()
this will be printed

It’s common to return inside an if statement, for example, to avoid errors.

def hr(width):
  if width < 0:
    print("Error: width can't be negative")
    return

  print("=" * width)
hr(-10)
Error: width can't be negative
hr(20)
====================

The return statement can optionally send a value back to the caller, so that the function call will then evaluate to that value.

def is_between(num, start_range, end_range):
    if num >= start_range and num <= end_range:
        return True
    else:
        return False

Then you can call the function anywhere you want to use the value it returns.

For example, assigning it to a variable…

from random import randint

height = randint(36, 108)
too_short = is_between(height, 1, 48)
words = ("can", "cannot")

print(f'A person of {height}" {words[too_short]} ride the ride.')
A person of 59" can ride the ride.

…in an if statement…

score = randint(-200, 200)

if not is_between(score, 1, 100):
    print(f"Error: Invalid score: {score}")
else:
    print(f"Your score is: {score}%")
Error: Invalid score: -40

…or as part of an expression.

rating = randint(0, 10)
text = is_between(rating, 1, 5) * f"Stars: {'*' * rating}"

if not text:
    print(f"Invalid rating: {rating}")
else:
    print(text)
Invalid rating: 7

Lets take a look at the difference between printing in the function, and returning.

def hello(name):
  print(f"hello {name}")
text = hello("you")
hello you
print(type(text))
<class 'NoneType'>
print(text)
None

When the function is called, the string "hello you" is printed. Since nothing is returned, text is None.

def hello(name):
  return f"hello {name}"
text = hello("you")
print(type(text))
<class 'str'>
print(text)
hello you

Nothing is printed when the function is called and text is assigned the string "hello you".

Part 3.1: Exercise#

Exercise 9 (random function)

Write a number() function to return a random number between 1 and 100.

Part 4: Docstrings#

Docstrings are a special kind of string in Python that are enclosed with three single ''' or double """ quotes. They can be used as a normal string that has the added bonus of being able to span multiple lines.

Their namesake, and the reason we are interested in them today, comes from the fact that when a docstring is the very first line of a file, function, or class, it serves as documentation.

def greet(time, name):
  """Return a greeting message based on the time of day"""
  message = "Good " + time + " " + name + "."
  return message

You can see this works like a comment while looking at the code. Niftier still, a functions docstring is saved by Python and can be used from the interpreters help() function.

Say we have the following greetings.py file:

Listing 54 greetings.py#
 1"""Functions for greeting people"""
 2
 3def hello(name):
 4    """Print hello to name"""
 5    message = "Hello " + name + "."
 6    print(message)
 7
 8def greet(time, name):
 9  """Return a greeting message based on the time of day"""
10  message = "Good " + time + " " + name + "."
11  return message

We could then import our functions from a Python shell, and call the help() on our own hello function.

Listing 55 Python shell#
>>> from greetings import hello
>>> help(hello)
Help on function hello in module greetings:

hello(name)
    Print hello to name

Or we could do the same thing for the whole greetings module:

Listing 56 Python shell#
>>> import greetings
>>> help(greetings)
Help on module greetings:

NAME
    greetings - Functions for greeting people

FUNCTIONS
    greet(time, name)
        Return a greeting message based on the time of day

    hello(name)
        Print hello to name

FILE
    .../greetings.py

Ideally all functions should have a simple doctring describing what the function does, any parameters, and any return value. For simple functions a one line brief description will do the trick.

For more complicated functions, you can take advantage of the multi-line abilities of docstrings to add detailed information. Here’s a long docstring example.

 1def prettify(message, align, width):
 2    """Return a formatted message
 3
 4    Params
 5    ------
 6    message (str): Message to format
 7    align (str): Alignment of text (left, center, right)
 8    width (int): Width of text
 9
10    Returns
11    -------
12    message (str): formatted message
13
14    Examples
15    --------
16    >>> prettify("hello", "center", 100)
17    '            hello             '
18    >>> prettify("goodbye", "right", 100)
19    '                       goodbye'
20    """
21
22    if align not in ("left", "center", "right"):
23      print(f"Invalid align argument: '{align}'")
24      return
25
26    if align == "center":
27      message = message.center(width)
28    elif align == "right":
29      message = message.rjust(width)
30
31    return message

Part 5: Exercises#

Part 5.1: welcome() function#

Exercise 10 (welcome)

Write a function named welcome that prints "Welcome to coding class!"

>>> welcome()

Part 5.2: letter_count() function#

Exercise 11 (letter_count)

Write a function called letter_count that takes one argument text and prints "There are __ characters in '___'." Call it multiple times with different arguments.

Part 5.3: is_vowel() function#

Exercise 12 (is_vowel)

a. Write a function named is_vowel that returns True if a character is a vowel and False otherwise. Don’t print anything in the function. Bonus: make it case-insensitive.

>>> is_vowel("a")
True

>>> is_vowel("E")
True

>>> is_vowel("c")
False

>>> is_vowel("something")
False

b. Call the function with a letter assign the result to a variable like answer. Print "is '_____' a vowel?: ___". (Note: this should be outside of the function.) Do this same thing with multiple arguments.

Part 5.4: tip() function#

Exercise 13 (tip)

a. Write a function tip that takes the arguments, cost and percent, and returns the tip amount. Do not print anything inside the function.

>>> tip(100, 20)
20.0

b. Call the function with an argument for cost and percent and assign the result to a variable like amount. Print the result like: "A ____% tip on a $_____ bill is: $_____". (Note: this should be outside of the function.) Do this same thing with multiple arguments.

Part 5.5: total() function#

Exercise 14 (total)

a. Write a function total that takes the arguments, bill and tip_percent, and returns the total including the tip. To calculate the tip call your tip() function from the total() function. Do not print anything inside the function.

>>> total(100, 20)
120.0

b. Call the function with an argument for bill and tip_percent and assign the result to a variable like final. Print the result like: "The final total on a $___ bill including a __% tip is: $_____". (Note: this should be outside of the function.) Do this same thing with multiple arguments.

Part 5.6: Docstring exercise#

Exercise 15 (docstrings)

Add a simple docstring to your file and all of the functions you’ve written today. Import them into a Python shell and use the help() function to view them.

Reference#

Glossary#

Functions#

argument#

A value that is passed as input to a function.

call#

code that tells the computer to execute the code within a previously defined function or method by using the function name followed by ( ), with any arguments inside the parenthisis.

define#
defining a function#

Creating a function by specifying its name, the parameters it takes, and what it does. In Python, this is done using the def keyword.

docstring#

a special kind of string surrounded by triple double-quotes """ or triple single-quotes ''' that can span multiple lines. When a docstring appears as the first expression in a file, module, class, or function it is stored by Python as documentation and can be seen by using the help() function in the Python shell.

function#

a named block of reusable code. A function may or may not take arguments, and may or may not return a value. In Python it is recommended to use the lower_case_with_underscores for function names.

keyword argument#

when arguments passed to a function are preceeded by the paramater name and an equals sign (=) so that they are assigned to the specified parameter regardless of the order in which they appear

parameter#

The named variables that appear in a function definition to specify the arguments it can accept.

positional argument#

when arguments are passed to a function so that they are assigned based on the order in which they appear

return#

a statement that can be used in a function to exit the function and optionally send a value to the caller

See Also#