In this blog you’ll learn to write
functions, which are named blocks of code
that are designed to do one specific job.
When you want to perform a particular task
that you’ve defined in a function, you call the name
of the function responsible for it. If you need to
perform that task multiple times throughout your program, you don’t
need to type all the code for the same task again and again; you just call
the function dedicated to handling that task, and the call tells Python to
run the code inside the function. You’ll find that using functions makes
your programs easier to write, read, test, and fix.
In this blog you’ll also learn ways to pass information to functions.
You’ll learn how to write certain functions whose primary job is to display
information and other functions designed to process data and return a
value or set of values.
Defining a Function
Here’s a simple function named greet_user() that prints a greeting:
def greet_user():
"""Display a simple greeting."""
print("Hello!")
greet_user()
The first line uses the keyword def to inform Python that you’re defining a function. Any indented lines that follow def greet_user(): make up the body of
the function. When you want to use this function, you call it. A function call tells
Python to execute the code in the function. To call a function, you write
the name of the function, followed by any necessary information in parentheses.
Passing Information to a Function
Modified slightly, the function greet_user() can not only tell the user Hello!
but also greet them by name. For the function to do this, you enter username
in the parentheses of the function’s definition at def greet_user(). By adding username here you allow the function to accept any value of username you
specify. The function now expects you to provide a value for username each
time you call it. When you call greet_user(), you can pass it a name, such as
'prasanna', inside the parentheses:
def greet_user(username):
"""Display a simple greeting."""
print("Hello, " + username.title() + "!")
greet_user('prasanna')
Output
Hello, Prasanna!
Entering greet_user('prasanna') calls greet_user() and gives the function the
information it needs to execute the print statement. The function accepts
the name you passed it and displays the greeting for that name.
Arguments and Parameters
The variable username in the definition of greet_user() is an example of a
parameter, a piece of information the function needs to do its job. The value
'prasanna' in greet_user('prasanna') is an example of an argument. An argument
is a piece of information that is passed from a function call to a function.
When we call the function, we place the value we want the function to work
with in parentheses.
Passing Arguments
Because a function definition can have multiple parameters, a function call
may need multiple arguments. You can pass arguments to your functions
in a number of ways. You can use positional arguments, which need to be in the same order the parameters were written; keyword arguments, where each
argument consists of a variable name and a value; and lists and dictionaries
of values. Let’s look at each of these in turn.
Positional Arguments
When you call a function, Python must match each argument in the function call with a parameter in the function definition. The simplest way to
do this is based on the order of the arguments provided. Values matched
up this way are called positional arguments.
To see how this works, consider a function that displays information
about pets. The function tells us what kind of animal each pet is and the
pet’s name, as shown here:
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('parrot', 'coco')
Output
I have a parrot.
My parrot's name is Coco.
Multiple Function Calls
You can call a function as many times as needed. Describing a second, different pet requires just one more call to describe_pet():
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('parrot', 'coco')
describe_pet('dog', 'Maski')
Output
I have a parrot.
My parrot's name is Coco.
I have a dog.
My dog's name is Maski.
You can use as many positional arguments as you need in your functions. Python works through the arguments you provide when calling the
function and matches each one with the corresponding parameter in
the function’s definition.
Order Matters in Positional Arguments
You can get unexpected results if you mix up the order of the arguments in
a function call when using positional arguments:
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('coco', 'parrot')
Output
I have a coco.
My parrot's name is Parrot.
If you get funny results like this, check to make sure the order of the
arguments in your function call matches the order of the parameters in the
function’s definition.
Keyword Arguments
A keyword argument is a name-value pair that you pass to a function. You
directly associate the name and the value within the argument, so when you
pass the argument to the function, there’s no confusion.
Keyword arguments free you from having
to worry about correctly ordering your arguments in the function call, and
they clarify the role of each value in the function call.
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(animal_type='parrot', pet_name='coco')
describe_pet(pet_name='coco', animal_type='parrot')
Output
I have a coco.
My parrot's name is Parrot.
I have a coco.
My parrot's name is Parrot.
Default Values
When writing a function, you can define a default value for each parameter.
If an argument for a parameter is provided in the function call, Python uses
the argument value. If not, it uses the parameter’s default value.
def describe_pet(pet_name, animal_type='dog'):
"""Display information about a pet."""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(pet_name='willie')
Output
I have a dog.
My dog's name is Willie.
Return Values
A function doesn’t always have to display its output directly. Instead, it can
process some data and then return a value or set of values. The value the
function returns is called a return value. The return statement takes a value
from inside a function and sends it back to the line that called the function.
Return values allow you to move much of your program’s grunt work into
functions, which can simplify the body of your program.
Returning a Simple Value
Let’s look at a function that takes a first and last name, and returns a neatly
formatted full name:
def get_formatted_name(first_name, last_name):
"""Return a full name, neatly formatted."""
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('Luke', 'Bryan')
print(musician)
Output
Luke Bryan
When you call a function that returns a value, you need to provide a
variable where the return value can be stored. In this case, the returned
value is stored in the variable musician. The output shows a neatly formatted name made up of the parts of a person’s name.
Returning a Dictionary
A function can return any kind of value you need it to, including more complicated data structures like lists and dictionaries. For example, the following function takes in parts of a name and returns a dictionary representing
a person:
def build_person(first_name, last_name):
"""Return a dictionary of information about a person."""
person = {'first': first_name, 'last': last_name}
return person
musician = build_person('jimi', 'hendrix')
print(musician)
Output
{'first': 'jimi', 'last': 'hendrix'}
This function takes in simple textual information and puts it into a
more meaningful data structure that lets you work with the information
beyond just printing it.
Passing a List
You’ll often find it useful to pass a list to a function, whether it’s a list of
names, numbers, or more complex objects, such as dictionaries. When you
pass a list to a function, the function gets direct access to the contents of
the list. Let’s use functions to make working with lists more efficient.
def greet_users(names):
"""Print a simple greeting to each user in the list."""
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)
Output
Hello, Hannah!
Hello, Ty!
Hello, Margot!
Modifying a List in a Function
When you pass a list to a function, the function can modify the list. Any
changes made to the list inside the function’s body are permanent, allowing
you to work efficiently even when you’re dealing with large amounts of data. Consider a company that creates 3D printed models of designs that
users submit. Designs that need to be printed are stored in a list, and after
being printed they’re moved to a separate list. The following code does this:
def print_models(unprinted_designs, completed_models):
"""
Simulate printing each design, until none are left.
Move each design to completed_models after printing.
"""
while unprinted_designs:
current_design = unprinted_designs.pop()
# Simulate creating a 3D print from the design.
print("Printing model: " + current_design)
completed_models.append(current_design)
def show_completed_models(completed_models):
"""Show all the models that were printed."""
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
Output
Printing model: dodecahedron
Printing model: robot pendant
Printing model: iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
Preventing a Function from Modifying a List
Sometimes you’ll want to prevent a function from modifying a list. In such case, you can send a copy of a list to a function like this:
print_models(unprinted_designs[:], completed_models)
The slice notation [:] makes a copy of the list to send to the function. The function print_models() can do its work because it still receives the
names of all unprinted designs. But this time it uses a copy of the original unprinted designs list, not the actual unprinted_designs list. The list
completed_models will fill up with the names of printed models like it did
before, but the original list of unprinted designs will be unaffected by the
function.
Passing an Arbitrary Number of Argument
Sometimes you won’t know ahead of time how many arguments a function
needs to accept. Fortunately, Python allows a function to collect an arbitrary number of arguments from the calling statement.
For example, consider a function that builds a pizza. It needs to accept a
number of toppings, but you can’t know ahead of time how many toppings
a person will want. The function in the following example has one parameter, *toppings, but this parameter collects as many arguments as the calling
line provides:
def make_pizza(*toppings):
"""Print the list of toppings that have been requested."""
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
Output
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
Mixing Positional and Arbitrary Arguments
If you want a function to accept several different kinds of arguments, the
parameter that accepts an arbitrary number of arguments must be placed
last in the function definition. Python matches positional and keyword
arguments first and then collects any remaining arguments in the final
parameter.
rameter.
For example, if the function needs to take in a size for the pizza, that
parameter must come before the parameter *toppings:
def make_pizza(size, *toppings):
"""Summarize the pizza we are about to make."""
print("\nMaking a " + str(size) +
"-inch pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
In the function definition, Python stores the first value it receives in
the parameter size. All other values that come after are stored in the tuple
toppings. The function calls include an argument for the size first, followed
by as many toppings as needed.
Output
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
Using Arbitrary Keyword Arguments
Sometimes you’ll want to accept an arbitrary number of arguments, but you
won’t know ahead of time what kind of information will be passed to the
function. In this case, you can write functions that accept as many key-value
pairs as the calling statement provides. One example involves building user
profiles: you know you’ll get information about a user, but you’re not sure
what kind of information you’ll receive. The function build_profile() in the following example always takes in a first and last name, but it accepts an
arbitrary number of keyword arguments as well:
def build_profile(first, last, **user_info):
"""Build a dictionary containing everything we know about a user."""
profile = {}
u
profile['first_name'] = first
profile['last_name'] = last
v
for key, value in user_info.items():
profile[key] = value
return profile
user_profile = build_profile('albert', 'einstein',
location='princeton',
field='physics')
print(user_profile)
Output
{'first_name': 'albert', 'last_name': 'einstein',
'location': 'princeton', 'field': 'physics'}
The definition of build_profile() expects a first and last name, and
then it allows the user to pass in as many name-value pairs as they want. The
double asterisks before the parameter **user_info cause Python to create
an empty dictionary called user_info and pack whatever name-value pairs it
receives into this dictionary. Within the function, you can access the namevalue pairs in user_info just as you would for any dictionary.
You can mix positional, keyword, and arbitrary values in many different ways when writing your own functions. It’s useful to know that all
these argument types exist because you’ll see them often when you start
reading other people’s code. It takes practice to learn to use the different
types correctly and to know when to use each type. For now, remember to
use the simplest approach that gets the job done. As you progress you’ll
learn to use the most efficient approach each time.
Storing Your Functions in Modules
One advantage of functions is the way they separate blocks of code from
your main program. By using descriptive names for your functions, your
main program will be much easier to follow. You can go a step further by
storing your functions in a separate file called a module and then importing
that module into your main program. An import statement tells Python to
make the code in a module available in the currently running program file.
Storing your functions in a separate file allows you to hide the details of
your program’s code and focus on its higher-level logic. It also allows you to
reuse functions in many different programs. When you store your functions
in separate files, you can share those files with other programmers without
having to share your entire program. Knowing how to import functions
also allows you to use libraries of functions that other programmers have
written.
There are several ways to import a module, and I’ll show you each of
these briefly.
Importing an Entire Module
To start importing functions, we first need to create a module. A module
is a file ending in .py that contains the code you want to import into your program. While importing you simply write import followed by the name of the module, makes every function from the module
available in your program. If you use this kind of import statement to import
an entire module named module_name.py, each function in the module is
available through the following syntax:
module_name.function_name()
In file pizza.py,
def make_pizza(size, *toppings):
"""Summarize the pizza we are about to make."""
print("\nMaking a " + str(size) +
"-inch pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
In file making_pizzas.py,
import pizza
pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
When we run making_pizzas.py,
Output
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
Importing Specific Functions
You can also import a specific function from a module. Here’s the general
syntax for this approach:
from module_name import function_name
You can import as many functions as you want from a module by separating each function’s name with a comma:
from module_name import function_0, function_1, function_2
The making_pizzas.py example would look like this if we want to import
just the function we’re going to use:
from pizza import make_pizza
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
Using as to Give a Function an Alias
If the name of a function you’re importing might conflict with an existing name in your program or if the function name is long, you can use a
short, unique alias—an alternate name similar to a nickname for the function. You’ll give the function this special nickname when you import the
function.
Here we give the function make_pizza() an alias, mp(), by importing
make_pizza as mp. The as keyword renames a function using the alias you
provide:
from pizza import make_pizza as mp
mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')
Using as to Give a Module an Alias
You can also provide an alias for a module name. Giving a module a short
alias, like p for pizza, allows you to call the module’s functions more quickly.
Calling p.make_pizza() is more concise than calling pizza.make_pizza():
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
Importing All Functions in a Module
You can tell Python to import every function in a module by using the asterisk (*) operator:
from pizza import *
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
Conclusion
In this blog you learned how to write functions and to pass arguments
so that your functions have access to the information they need to do their
work. You learned how to use positional and keyword arguments, and how
to accept an arbitrary number of arguments. You saw functions that display
output and functions that return values. You learned how to use functions
with lists, dictionaries, if statements, and while loops. You also saw how to
store your functions in separate files called modules, so your program files
will be simpler and easier to understand.
One of your goals as a programmer should be to write simple code that
does what you want it to, and functions help you do this. They allow you to
write blocks of code and leave them alone once you know they work. When
you know a function does its job correctly, you can trust that it will continue
to work and move on to your next coding task.
Functions allow you to write code once and then reuse that code as
many times as you want. When you need to run the code in a function,
all you need to do is write a one-line call and the function does its job.
When you need to modify a function’s behavior, you only have to modify
one block of code, and your change takes effect everywhere you’ve made a
call to that function.
Using functions makes your programs easier to read, and good function names summarize what each part of a program does. Reading a series
of function calls gives you a much quicker sense of what a program does
than reading a long series of code blocks.
Functions also make your code easier to test and debug. When the bulk
of your program’s work is done by a set of functions, each of which has a
specific job, it’s much easier to test and maintain the code you’ve written.
You can write a separate program that calls each function and tests whether
each function works in all the situations it may encounter. When you do
this, you can be confident that your functions will work properly each time
you call them.
Post a Comment
Let's make it better!
Comment your thoughts...