Functions
Function videos
Python Tutorial for Beginners 8: Functions
Define a function
pass
How to execute a function
Benefits of using functions
Return values
Defining parameters
Default parameters
- Advanced-level topics beyond
10:30
(optional viewing) *args
and**kwargs
- Advanced-level topics beyond
Python Tutorial: Variable Scope (watch until
9:20
)Local variables
Global vairables
Python Tutorial for Beginners 9: Import Modules and Exploring The Standard Library (watch until
6:30
)Python Tutorial: if __name__ == ‘__main__’ (Optional)
Note: Corey is using Python 2 (old) for this video. Just use the
print
function like you are used to.
Anatomy of a Function
Calling a function
Up to this point, you are familiar with coding a single program. In reality, a program is made up of smaller sub-programs. We call those sub-programs functions. If you look closely at the following code, you will notice you have been using functions the whole time:
1name = input("Please enter your name: ")
2message = f"Hello, {name}. Nice to meet you."
3print(message)
On line #1, we are calling the input
function, and on line #2, we are calling the print
function.
Any time you see some name with parentheses following it some_name()
, it is most likely a function.
The input
and print
functions were written by someone else and Python automatically includes them as built-in functions.
We can also define our own functions that we can use. In fact, when working as a software developer, the majority of
the code you write will be in functions. We will see how to define custom functions a little later.
Passing arguments
Most functions require some information so they can do their job. Take a look at the function below.
1def add(a: int, b: int) -> int:
2 return a + b
In the function definition on line #1, in the brackets, the defined function tells us it needs two integers to do its job. Therefore, when we call the funciton we need to give it those arguments. In this case, two integers.
add(5, 7)
Each individual argument is separated by a comma. Arguments can be of any data-type. The function definition tells us exactly how many arguments and what datatypes.
Here is another function definition with different datatypes.
def repeat_message(message: str, times: int) -> str:
pass
It defines two required arguments: a message of type str
and the number of times (of type int
) to repeat the message. To call repeat_message
we need to supply a str
and an int
as arguments.
repeat_message("hello", 5)
Handling return values
Most of the time when writing and using functions, you want the function to go off, do some work for you and return with some result.
Imagine you have a friend (some function) that will do your homework for you. You give it the specific questions you need to complete (arguments) and then wait for them to finish it.
Now imagine, they look at the questions and just yelled out the answers wherever they were. Aside from that being hilarious,
it would be useless to you since you would not have anything to turn in to your teacher. This is like using print
in your functions.
A lot of beginner programmers love to use print
for everything. Sometimes you can use print
in functions, but moving forward,
I would like to formally discourage using print in functions (outside of debugging or showing a user interface like printing menu options).
When your friend (the function) completes your homework, it is critical that they give it back to you so you can accomplish the next step of turning it in. If this situation were code, it could potentially look like.
1homework_subject = "math"
2homework_chapter = "chapter 1"
3completed_work = get_friend_to_do_your_homework(homework_subject, homework_chapter)
4hand_in(completed_work)
Line #3: call the function get_friend_to_do_your_homework
and give it the subject and chapter arguments.
The function will go off and do its job, then return the completed homework. Your program will then store that completed homework
in a variable called completed_work
.
Line #4: Calls the function hand_in
and gives it the completed_work
.
In a more practical example, line 9 below calls a function to calculate the tax and stores the result in a variable called tax
.
1def calc_tax(amount: float) -> float:
2 TAX_RATE = 0.13
3 return amount * TAX_RATE
4
5
6cost = 6.99
7quantity = 3
8subtotal = cost * quantity
9tax = calc_tax(subtotal)
10total = subtotal + tax
Most of the time the pattern will be like that.
def some_function():
return "some return value"
result = some_function()
Call the function, get the result and decide what to do with the result outside of the function.
Note
Why not print things from within the functions themselves?
One person using the function might want to print out the result right away. Someone else might want to do some further processing on the result before printing it out. We want to have our functions do only the bare minimum (i.e., just calculate a value rather than also printing it out) to prevent any undesired side-effects. At best, other developers will not want to use our functions, at worse they will curse us because they will have to modify/rewrite them.
Defining a Function
Defining a function is much like initializing a variable. Instead of storing a number or a string like in a variable, in a function we store a whole bunch of code.
What we need (at a minimum):
a function name
some code to save in the function.
def function_name():
print("Some code saved in a function")
Every line of code that is stored in the function is indented underneath the function header starting with def
.
Recall that, in order to actually run the function’s code, we need to call the function.
Returning a value
When a function gives back some result. See line 2:
1def add(a: int, b: int) -> int:
2 return a + b
I like to think of functions as a worker or a friend you know, who can get a specific job done for you. Imagine an intelligence agency needs someone to go and search the database for all mentions of a praticular person of interest.
Intelligence Director: I need the full profiles of everyone matching the last name McGee
. I will wait here patiently until you come back with that list. Hurry up!
What are they looking for and what information are they providing? They are looking for “profiles” and they are poviding a last name, “McGee” to be exact. In code, this could look like:
full_profiles = get_profiles_with_name("McGee")
The intelligence director would be Calling a function (get_profiles_with_name
) and functions:passing an argument ("McGee"
).
Low-level Intelligence Agency Data-gatherer: Yes, ma’am! I will take this name
and get to work!
The low-level intelligence agency data-gatherer was trained to return a list of profiles when someone provided a name. The function definition for this data-gatherer would look like:
def get_profiles_with_name(name: str) -> List[Profile]:
# some code
# processing....
# still processing....
return list_of_profiles
Notice the last thing the data-gatherer does is return the result they were trained to do.
Low-level Intelligence Agency Data-gatherer: Here is the folder full of the profiles you requested.
Intelligence Director: Thank you for these profiles. Now I must sort through them and come up with a candidate for my boss.
The flow of information would look like:
Warning
Under construction
Defining parameters
Some functions require no outside information in order to run. This can be slightly restrictive:
def move_ten_meters():
"""The robot moves ten meters""".
pass
move_ten_meters()
What if you wanted the robot to move 15
meters? Would you create a move_fifteen_meters
function?
More useful functions require some outside information to run. We can define functions with certain parameters.
In the case below, we are defining a move
function to have a meters
parameter:
1def move(meters: float):
2 """The robot will move the provided number of meters.
3
4 Args:
5 meters: The number of meters you want the robot to move.
6 """
7 print(f"Moving robot {meters} meters.")
8 # more code actually moving the robot
9 # ...
10
11move(15)
Notice how the function has access to the value (15
) that was passed to it. It accesses the value (on line #7) through the parameter-variable named meters
.
Type annotations
Below is a list of common types to use when annotating Python Functions. Some need to be imported from the Python typing library:
from typing import List, Tuple, Dict, Optional
some_integer: int
some_string: str
some_float: float
list_of_integers: List[int]
tuple_with_an_int_and_a_string: Tuple[int, str]
two_dimensional_list_of_integers: List[List[int]]
either_an_integer_or_none: Optional[int] = None
Docstrings
A docstring is a multi-line comment to explain in a very concise manner the purpose of a function and how to use it.
To use a funciton you need to know:
its name
what arguments to pass to it
what it will return back to you
Have a look at the basic format for docstrings:
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
"""Example function with PEP 484 type annotations.
Args:
param1: The first parameter.
param2: The second parameter.
Returns:
The return value. True for success, False otherwise.
"""
pass
For docstrings pertaining to Classes, see Docstrings (Classes).