Writing Functions#
Learning Objectives
Questions:
How can I create my own functions?
Objectives:
Explain and identify the difference between function definition and function call.
Write a function that takes a small, fixed number of arguments and produces a single result.
Identify local and global variables.
What are functions?#
In Python, a function is like a little machine in your code: you give it a name, tell it what steps to perform, and then you can use it whenever you need that task done. Instead of copying and pasting the same code over and over, you can just “call” the function and let it do the work for you. This makes your programs shorter, easier to read, and much simpler to update.
You have already met some of Python’s built-in functions - things like print(), type(), and len(). Both functions and methods are recognized by their name followed by parentheses (), which is how you call them to perform an action.
Built-in functions are great, but sometimes you might want something that is made just for your program. That is where user-defined functions come in - you can create your own!
Here are a few key things to know about functions:
A function is a block of code that only runs when you call it.
Once defined, you can reuse it as many times as you like without rewriting the code.
You can send information into a function - these are called parameters.
A function can give something back - this is called its return value.
Use functions to make your code easier to understand#
Human beings can only keep a few items in working memory at a time. However, we can handle larger and more complex ideas by organizing them into manageable units and treating them as single concepts. Functions serve a similar purpose in Python. We can create our own functions to encapsulate complexity and treat specific actions or ideas as a single “thing”. Functions also enable us to re-use code so we can write code one time, but use it many times.
Defining a function#
You define a function using def with a name, parameters, and a block of code.
Begin each definition of a new function with the keyword def (for “define”), followed by the name of the function. Function names follow the same rules as variable names.
Next, add your parameters in parentheses. You should still use empty parentheses if the function does not take any inputs.
Finally, like in conditionals and loops, you will add a colon and an indented block of code that will contain the body of your function.
def print_greeting():
print('Hello!')
This code defines a function named print_greeting that prints the text Hello! when it is called.
Defining a function does not run it#
Note that we do not have any output when we run code to define a function. This is similar to assigning a value to a variable. The function definition is sort of like a recipe in a cookbook - the recipe does not create a meal until we use it. So we need to “call” a function to execute the code it contains. This means that Python will not show you errors in your function until you call it. So when a definition of a function runs without error it does not mean that there will not be errors when it executes later.
print_greeting()
Matching arguments and parameters#
Functions are most powerful when they can take in data.
Parameters are names you list in the function definition. They act like placeholders.
Arguments are the actual values you pass in when calling the function.
Python matches arguments to parameters by position (or by name).
This means:
If a function defines a parameter, you must provide a matching argument when you call it (unless the parameter has a default value).
If you pass an argument that has no corresponding parameter, Python will raise an error.
Likewise, if a parameter is required but you do not provide an argument, you will also get an error.
In other words, parameters and arguments must match: you can only use data inside a function if there is a parameter defined for it, and you must give an argument for every parameter that requires one.
def print_named_greeting(name):
print(f'Hello {name}!')
print_named_greeting('World')
To expand on the recipe metaphor above, the arguments you add to the () contain the ingredients for the function, while the body contains the recipe.
Functions with defined parameters will result in an error if they are called without passing an argument:
print_named_greeting()
Default parameter values#
Sometimes it is useful to make a parameter optional by giving it a default value. This means the function will use the default if no argument is provided.
def print_named_greeting(name='World'):
print(f'Hello {name}!')
Now the function can be called both with and without an argument:
print_named_greeting('Alice') # argument overrides the default
print_named_greeting() # no argument, so the default is used
In the first call, the argument 'Alice' is used as the value of name.
In the second call, no argument is provided, so the default value 'World' is used instead.
Use return to pass values back from a function#
In the examples above, we printed the results of the function code to output, but there are other ways to handle data and objects created within a function. We can use the keyword return to send a value back to the “global” environment. (We will learn about local and global variables below). A return command can occur anywhere in the function, but is often placed at the very end of a function with the final result.
def get_book_label(book_info):
label = f"{book_info['title']} by {book_info['author']}"
return label
book = {
"title": "1984",
"author": "George Orwell",
"year": 1949
}
label = get_book_label(book)
# Notice that the function parameter is called book_info,
# even though we pass in a variable called book.
# The names do not have to match.
print(label)
A function that does not explicitly return a value will automatically return None.
def print_book_label(book_info):
label = f"{book_info['title']} by {book_info['author']}"
print(label)
book = {
"title": "1984",
"author": "George Orwell"
}
result = print_book_label(book)
# The function prints the label, but does not return a value.
# So the variable 'result' is assigned None.
print(f"Result of call is: {result}")
Variable scope#
When we define a variable inside of a function in Python, it is known as a local variable, which means that it is not visible to – or known by – the rest of the program. Variables that we define outside of functions are global and are therefore visible throughout the program, including from within other functions. The part of a program in which a variable is visible is called its scope.
This is helpful for people using or writing functions, because they do not need to worry about repeating variable names that have been created elsewhere in the program.
# user is a global variable (a dictionary)
user = {
"name": "Alice",
"role": "student"
}
def describe_user(age):
# age is a local variable (parameter)
description = f"{user['name']} is {age} years old and is a {user['role']}."
return description
result = describe_user(25)
# The function returns a string, so 'result' stores that value
print(result)
print(age) # NameError: age is not defined outside the function
Explanation
useris a global variable (a dictionary), defined outside the functionageis a local variable (a parameter), only available inside the functiondescriptionis also a local variable, created inside the function
Even though user is defined outside the function, it can still be used inside it.
Local variables, on the other hand, only exist within the function where they are defined.
Even though description is a local variable, we can still access its value outside the function because it is returned. The return statement sends the value back to the place where the function was called, where it can be stored in a new variable (in this case result) and used in the rest of the program.
# Trying to access a local variable outside the function will cause an error
print(age) # NameError: name 'age' is not defined
Global variables can be accessed inside functions
Local variables only exist inside the function where they are defined
Variables with the same name in different scopes do not interfere with each other
Use docstrings to provide online help#
If the first thing in a function is a string that is not assigned to a variable, that string is attached to the function as its documentation. This kind of documentation at the beginning of a function is called a docstring.
Docstrings are useful because they describe what a function does, what input it expects, and what it returns. They can also be accessed using Python’s built-in help() function.
def get_role(user_info):
"Return the role of a user."
return user_info["role"]
This is helpful because we can now ask Python’s built-in help system to show us the documentation for the function:
help(get_role)
We do not need to use triple quotes when we write a docstring, but if we do, we can break the string across multiple lines:
def get_role(user_info):
"""Return the role of a user.
Input:
user_info (dict): A dictionary containing user data
Output:
str: The role of the user
"""
return user_info["role"]
help(get_role)
Exercises#
Exercise 1: Create a function#
Write a function called addition that takes two parameters and returns their sum. After defining the function, call it with several arguments and print out the results.
Solution
def addition(x, y):
return x + y
print(addition(2, 4))
print(addition(3, 6))
print(addition(4, 8))
6
9
12
Exercise 2: Local and global variables#
List all of the global variables and all of the local variables in the following code.
playlist = {
"song": "Imagine",
"artist": "John Lennon",
"year": 1971
}
def describe_song(song_data):
info = f"{song_data['song']} by {song_data['artist']} was released in {song_data['year']}."
return info
result = describe_song(playlist)
print(result)
playlistis a global variableresultis a global variablesong_datais a local variable (parameter)infois a local variable
Exercise 3: Dictionary lookup#
Create a function called get_capital that takes the name of a country as its parameter and returns the capital city using a dictionary.
If the country is not found in the dictionary, the function should return "Country not found".
After defining the function, ask the user to enter a country and print the result.
Hint:
Use
.get()to safely access values in the dictionaryRemember that user input may need to be converted (e.g., using
.lower())
Solution
def get_capital(country):
capitals = {
"denmark": "Copenhagen",
"france": "Paris",
"germany": "Berlin",
"spain": "Madrid"
}
return capitals.get(country.lower(), "Country not found")
country = input("Enter a country: ")
print(get_capital(country))
The function get_capital uses a dictionary to store pairs of countries and their capitals. Inside the function, we use the .get() method to look up the value associated with the given country.
Before performing the lookup, we convert the input to lowercase using .lower(). This ensures that the function works regardless of how the user types the country name, for example "Denmark", "denmark", or "DENMARK".
The .get() method returns None if the key is not found. In this solution, we provide the custom default value "Country not found", so the function returns that message instead of None.
Finally, the function returns the result, which is then printed after calling the function.
Key points#
Break programs down into functions to make them easier to understand.
Define a function using
defwith a name, parameters, and a block of code.Defining a function does not run it.
Arguments in call are matched to parameters in definition.
Functions may return a result to their caller using
return.