Functions, Loops, and Logic
The core of Python programming is conditional if/else/elif control statements, loops, and functions. These are powerful tools that you must master to solve problems and implement algorithms. Use these materials to practice their syntax. If/else/elif blocks allow your program to make conditional decisions based upon values available at the time the block is executed. Loops allow you to perform a set of operations a set number of times based on a set of conditions. Python has two types of loops: for loops and while loops. For loops work by counting and terminating when the loop has executed the prescribed number of times. While loops work by testing a logical condition, and the loop terminates when the logical condition evaluates to a value of false. Functions are designed to take in a specific set of input values, operate on those values, and then return a set of output results.
Loops
for
loops
Looping in Python doesn't look like looping in other languages.
If you write JavaScript, Java, or other languages, you might have seen code that looks something like this code, that keeps track of 3 things: the starting index, the condition the loop will run until, and which action to take (in this case, incrementing the variable i
by 1) until the condition is met.
for (i = 0; i < 5; i++) {
text += "The number is " + i + "<br>";
}
In fact, before these languages introduced something called a
for each
loop, this was also the clunky way you'd loop through items in a sequence.
Looping in Python
Looping in Python is a simpler, cleaner process because the Python language prides itself on readability.
Remember you used the in
keyword to test if an item was in a sequence? When combined with the for
keyword, in
can be used to indicate looping over each item in the sequence.
The syntax is: 1. for single_item in items
1. followed by a colon :
1. followed by a new line 1. start a level of indentation 1. Add the code you'd like to consider as the body of the loop. That is, the code that'll run multiple times, until there are no more items in the collection. 1. If running on the REPL, press enter again
Let's see it in action.
>>> colors = ["Red", "Green", "Blue", "Orange"]
>>> for color in colors:
... print(f"The color is: {color}")
...
The color is: Red
The color is: Green
The color is: Blue
The color is: Orange
Looping over a range of numbers
Let's say we wanted to duplicate the code in the example JavaScript above, that prints out the numbers from 0 to 4.
In order to do this, we'll need to use a built-in function called range()
. The range function in python produces a sequence of integers from an optional and inclusive start, to a defined and exclusive finish.
In Python2, this function created a list of each number in that sequence. As you can imagine, it was horribly inefficient for large ranges. In Python3, the range()
function returns a new optimized data type. It's great for optimization, but it's harder for debugging.
Note: If you want to explicitly see what a call to range()
produces for debugging purposes, you can pass the result into the list()
method to see all the values at once. For example: list(range(5))
. Remember that this is inefficient, so use it for testing, not in production code.
If we wanted to loop over all the values from 0 to 4, we'd use the range function like this:
>>> for num in range(5):
... print(f"The number is: {num}")
...
The number is: 0
The number is: 1
The number is: 2
The number is: 3
The number is: 4
You'll notice that this call didn't include the number 5.
What if we wanted the range from 1 to 4, instead of 0 to 4?
range()
can be called with start
and stop
parameters, and the range will start from start
.>>> for num in range(1, 5):
... print(f"The number is: {num}")
...
The number is: 1
The number is: 2
The number is: 3
The number is: 4
You can also pass an a third optional
step
parameter in. Let's say I quickly wanted to print out all the even numbers from 2 to 10. I would call range(2, 11, 2)
. Remember, 2 is where we're starting, 11 is one higher than where we're ending (10), and 2 is the step, or the amount to jump between numbers.>>> for num in range(2, 11, 2):
... print(f"The number is: {num}")
...
The number is: 2
The number is: 4
The number is: 6
The number is: 8
The number is: 10
What do inclusive and exclusive mean in this context? Exclusive means that the end result will not include that number. If you'd like the numbers from 0 to 4, you would call
range(5)
. Consider 5 to the stopping point. Inclusive means the range will include the number. The start
parameter is inclusive, meaning if you'd like the range of numbers from 1 to 4, you'd call range(1, 5)
.Tip: If you can't remember how to use range, don't forget to call
help(range)
from the command line.
Looping over items with the index using enumerate
.
In Python, we avoid writing code like the JavaScript for
loop at the top, but sometimes it's unavoidable, and we need a way to access the index of the items we're looping through. To do that we use a special function called enumerate()
. The function takes a sequence, like a list
, and it returns a list
of tuples, containing the index of the item in the sequence, and the sequence itself.
Don't worry about the list of tuples for now, but remember our tuple unpacking from earlier?
>>> point = (2, 5, 11)
>>> x, y, z = point
>>> x
2
>>> y
5
>>> z
11
Because
enumerate()
returns a structure that looks like a list of tuple
s under the hood, we can take advantage of tuple unpacking in the for
loop.>>> for index, item in enumerate(colors):
... print(f"Item: {item} is at index: {index}.")
...
Item: Red is at index: 0.
Item: Green is at index: 1.
Item: Blue is at index: 2.
Item: Orange is at index: 3.
Tip: Remember, indicies in Python start at zero.
Looping over a dictionary
Now that we know we can use tuple unpacking in a for loop, let's go over how to loop over a dictionary.
Let's say we have a dictionary of colors with their hex color code used for HTML in websites.
>>> hex_colors = {
... "Red": "#FF0000",
... "Green": "#008000",
... "Blue": "#0000FF",
... }
Warning: Remember, a dictionary is composed of key, value pairs. When we loop over a dictionary with the
for item in my_dict
syntax, we'll end up looping over just the keys.In this example, notice how we're looping over the wrong thing:
>>> for color in hex_colors:
... print(f"The value of color is actually: {color}")
...
The value of color is actually: Red
The value of color is actually: Green
The value of color is actually: Blue
Tip: If we want to loop over the key, value pairs in a dictionary, we'll want to call
my_dict.items()
.We can use tuple unpacking along with the
my_dict.items()
list to loop over both the keys and the values at the same time.>>> for color, hex_value in hex_colors.items():
... print(f"For color {color}, the hex value is: {hex_value}")
...
For color Red, the hex value is: #FF0000
For color Green, the hex value is: #008000
For color Blue, the hex value is: #0000FF
Common Errors
What if you try to loop over key, value pairs, and forget to use my_dict.items()
?
>>> for color, hex_value in hex_colors:
... print(f"For color {color}, the hex value is: {hex_value}")
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
Info: You'll see
ValueError: too many values to unpack (expected 2)
if you forget to call my_dict.items()
, and try to loop over what you'd expect to be key, value pairs.
Additional Resources
If you really want to be a pro at looping in a Pythonic way, I recommend watching Raymond Hettinger's talk - Transforming Code into Beautiful, Idiomatic Python after this course.
while
loops
while
loops are a special type of loop in Python. Instead of running just once when a condition is met, like an if
statement, they run forever until a condition is no longer met.while
loops usually need to be accompanied by an always changing sentinel value.
>>> counter = 0
>>> max_val = 4
>>>
>>> while counter < max_val:
... print(f"The count is: {counter}")
... counter = counter + 1
...
The count is: 0
The count is: 1
The count is: 2
The count is: 3
Warning: Our loop will run forever if we forget to update the sentinel value. Press Ctrl-C to exit the infinite loop.
# Warning: don't copy and paste this example.
>>> counter = 0
>>> max_val = 4
>>> while counter < max_val:
... print(f"The count is: {counter}")
...
# What happens if we don't update counter?
The count is: 0
The count is: 0
The count is: 0
The count is: 0
# An infinite loop repeated until we hit Ctrl-C
The count ^CTraceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
Loops and the return
statement
Just like in functions, consider the return
statement the hard kill-switch of the loop.
>>> def name_length(names):
... for name in names:
... print(name)
... if name == "Nina":
... return "Found the special name"
...
>>> names = ["Max", "Nina", "Rose"]
>>> name_length(names)
Max
Nina
'Found the special name'