Functions, Loops, and Logic

Site: Saylor Academy
Course: CS250: Python for Data Science
Book: Functions, Loops, and Logic
Printed by: Guest user
Date: Thursday, 10 April 2025, 3:03 PM

Description

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.

Introduction

Functions help us organize our code in a way that's reusable, and accept arguments and defaults where needed. Loops let us take action on collections of items. Boolean logic allows us to control the execution flow of our program.


Source: Nina Zakharenko, https://practical.learnpython.dev/04_functions_and_loops/
Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 License.

Running .py files

Creating Python Files with the *.py extension

You know a file is a Python program when it ends with a .py extension.


Naming Tips

Just like with formatting, Python's PEP8 guidelines give us a few helpful tips about how to name our Python program files.

In Python:

  1. Filenames should be *all lowercase
  2. Words should be separated with underscores _
  3. Filenames should be short
Some good example filenames:
  • apis.py
  • exceptions.py
  • personal_blog.py
Some bad example filenames:
  • MYFILE.PY
  • CamelCaseFile.py
  • really_long_over_descriptive_project_file_name.py


What are *.pyc files?

For optimization and other reasons, Python code can be compiled to intermediary .pyc files. The good news is you don't have to worry about them. The bad news is, very occasionally stale versions of these compiled files can cause problems. To safely delete them from the current project directory, run find . -name "*.pyc" -delete (on linux or macOS).



git tip: use a .gitignore for Python

If you use git for source control, you'll want to make sure that these compiled *.pyc files are ignored and not added to your repository.

The best way to do this is to add the standard .gitignore file for Python to your project.


Running Python Files From VS Code

Running Python files from VS Code is really quick and easy.

Creating New Python Files

To create a new file in VS Code, hit Ctrl + N on Windows and Linux, and Cmd + N on macOS.

This will open a new file. Next, save the file with a .py extension.

Info

Create a new simple Python program in a file called hello.py in our pyworkshop directory with the following contents:

# in file: hello.py
greetings = ["Hello", "Bonjour", "Hola"]

for greeting in greetings:
    print(f"{greeting}, World!")

Opening The VS Code Terminal Window

Next, you'll need to open your terminal if you don't have it open already. The quick keyboard shortcut to do that is Ctrl - `

Note

If you already had your Python REPL open, you'll need to select a terminal with a shell in it (generally, the one labeled with 1:).


Running The File

Once you've opened your hello.py file and selected your new terminal window, open the VS Code command palette.

Note

Open the command palette with Ctrl+Shift+P on Windows and Linux, and Cmd + Shift + P on macOS.

Select Python: Run Python File in Terminal

You should see:

Hello, World!
Bonjour, World!
Hola, World!

How easy was that?


Running Python Files From a Non-VS Code Terminal

If you want to run a Python file without using the command palette, just open your terminal of choice, cd into the directory with your code, and type in the command python followed by a space, and the name of your Python program. Don't forget to activate your virtual environment like we did in the Environment Setup section.

(env) $ python hello.py
Hello, World!
Bonjour, World!
Hola, World!
This also works in the VS Code terminal.


Printing Tips

One of the nice things about the REPL is we can quickly and easily see the contents of our variables, just by typing their name and pressing enter. Unfortunately, running code from Python files doesn't do quite the same thing.

In a file named name.py:

# file name.py
name = "Nina"
name
Output:
(env) $ python name.py
Notice, there was no output.

Now, in a file named print_name.py:
# file print_name.py
name = "Nina"
print(name)
Output:
(env) $ python name.py
Nina
Hooray! Now we see some output.

Tip

If you want to see any output from your Python programs, you'll need to use print().


Debugging Your Code With print()

As your Python programs become more complicated, you'll want to do some basic debugging to figure out what's going on under the hood. For beginners, using print() is a great way to accomplish that goal.

Note

If you write Python code on a team or plan on sharing it, it's a good idea to remove your debugging print()s before you share your code with others.

In a Python file named mystery.py:


def mystery():
    num = 10 * 3

    if num == 10:
        print("Num was equal to 10")
        num = num * 10
    if num == 20:
        print("Num was equal to 20")
        num = num * 20
    if num == 30:
        print("Num was equal to 30")
        num = num * 30

    print(f"Value of returned num is: {num}")
    return num

mystery()
We'll see the output:
Num was equal to 30
Value of returned num is: 900

Tip: As you continue your Python journey, try using a debugger, like the built-in pdb instead of the print() function to really dive into what your code is doing under the hood.


Output Formatting Tips

If your Python program will have terminal output, you can use these tips to make it a little nicer.

Use new lines and tabs

Use control characters in your string to change how your output is represented.

  • \n for new line
  • \t for tab
In formatting_example.py:
# Use \n to add a new line, before, in the middle of, or after a string.
print("\nExtra New Line Before")
print("One Print\nTwo New Lines!")
print("Extra New Line After\n")

# Use \t to add a tab.
print("\t Here's some tabbed output.")

# Or, combine both!
print("\nOne Print\n\tOne Tab")
Output running: python3 formatting_example.py.
Extra New Line Before
One Print
Two New Lines!
Extra New Line After

         Here's some tabbed output.

One Print
        One Tab

Pretty Printing with pprint

When printing large data structures like long lists or big dictionaries, they come out on one line. It's a bit hard to read.

If you want a little bit of extra formatting, like having each element of a long list on a new line, you can use the included pprint module (stands for pretty print) in your files or in the REPL.

>>> long_list = list(range(23))

>>> print(long_list)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

>>> from pprint import pprint
>>> pprint(long_list)
[0,
 1,
 2,
 3,
 4,
 5,
 6,
 7,
 8,
 9,
 10,
 11,
 12,
 13,
 14,
 15,
 16,
 17,
 18,
 19,
 20,
 21,
 22]

Tip

This will become more useful as your Python programs become more complex.

Functions

Anatomy of a function

Functions allow us to create reusable code and avoid copy and pasting.

A function in Python is defined with the def keyword, followed by the function names, zero or more arguments or named arguments contained in parenthesis (), and a colon : to indicate the start of the function.

The contents of the function then follow, indented after the function definition.

Then, an optional return statement can follow, if the function plans on passing data back to the caller.

The recipe for a function in Python:

  1. def: the def keyword, telling Python we're about to start a function definition
  2. a name for the function
  3.  ( : opening parenthesis
  4. (optional) the names of one or more arguments, separated with ,
  5. (optional) the names and values of one or more default arguments, separated with ( , ) note: we'll see these in the next section
  6.  ) closing parenthesis
  7.  : a colon

# A Basic Function that accepts no arguments and returns nothing.
def hello_world():
    print("Hello, World!")


# A Function that accepts two arguments, and returns a value
def add_numbers(x, y):
    return x + y

Tip

If you get the syntax for a function wrong, Python will throw a SyntaxError.

For example, trying to create a function without the colon : :

>>> def hello_world()
  File "<stdin>", line 1
    def hello_world()
                    ^
SyntaxError: invalid syntax

And trying to create a function without the parenthesis () :

>>> def hello_world:
  File "<stdin>", line 1
    def hello_world:
                   ^
SyntaxError: invalid syntax

Indentation

One of the most important aspects of functions is indentation. Remember, Python doesn't use curly braces to figure out what's inside a function like other languages you may have seen, such as JavaScript or Java.

Python knows what code is related to a function by how it's indented. Anything that's indented one level deep under the function declaration is part of the function, no matter how many spaces there are between lines.

If you're using the REPL, once you're done entering your function, you'll need to press enter an additional time, to mark the end of the function. You know you're done defining your function when you see the 3 input arrows >>> again.

Type the following code in your REPL. Note that the 3 dots ... indicate that those lines are indented in the REPL. If you type your code in a Python file, you won't see the ... dots.

>>> def hello(name):
...     print("Hello", name)
...

See an error?

Note: If you get an IndentationError, that means that you didn’t correctly indent your code after your function definition. Try typing your function into the REPL one more time.

# The error you'll see if you didn't indent your function correctly.
>>> def add_numbers(x, y):
... return x + y
File "<stdin>", line 2
    return x + y
        ^
IndentationError: expected an indented block


Function Contents

The recipe for function contents:

  1. indentation (press tab on your keyboard)
  2. one or more lines of indented code
  3. (optional) a return statement

return statement

Using a return statement, you can optionally pass data back to the caller of the function.

with no return statement

If a function doesn't have a return statement, it implicitly returns None

>>> def foo():
...     x = 5
...
>>> val = foo()
>>> type(val)
<type 'NoneType'>

with a return statement, but no value

If a function has a return statement, but no value, it also returns None. This is typically used to control the flow of a program.


>>> def foo():
...     x = 5
...     return
...
>>> val = foo()
>>> type(val)
<type 'NoneType'>

with a return statement and a value

To return a value from a function, just type it after the return statement. You can return anything from a Python function, including other functions! For today, we'll focus on simple and complex data types.

>>> def foo():
...     x = 5
...     return x
...
>>> val = foo()
>>> val
5

As we explore simple functions, our return statements will usually be at the end of the function, but that's not the only way they can be used. A function can have multiple return statements, and those return statements can be used to control the flow of the program.

Note: Because it's syntactically correct to have multiple return statements in a function, it's up to you to use them correctly. If you use a linter for your code files and you place additional code in a function after a return statement, the linter will give you a warning that the rest of your code is unreachable.


Calling Functions

With no arguments

Once you've defined a function, you can call it from your Python code as many times as you'd like.

To call a Python function, type in it's name, along with parenthesis, and any required arguments to the function. Let's try it now, with a function that doesn't require arguments.


>>> def hello_world():
...     print("Hello, World!")
...
>>> hello_world()
Hello, World!

With arguments

Let's try it again, this time with a function that does accept arguments.

Tip

Here, note that the function accepts names for the arguments. But, when we call the function, we're passing in values.

>>> def add_numbers(x, y):
...     return x + y
...
>>> add_numbers(3, 5)
8
>>>

Storing the returned value of a function.

Storing the returned value of a function is easy. All you need to do is assign it to a variable.

Let's try it now.


>>> def add_numbers(x, y):
...     return x + y
...
>>> new_number = add_numbers(3, 5)
>>> new_number
8

The variable new_number now contains the result of running our add_numbers function with our arguments 3 and 5.

Arguments

Arguments in Practice

Positional arguments are required

Positional arguments are all required, and must be given in the order they are declared.

For example, this function doesn't do what we expected, because we passed in our arguments in the wrong order.

>>> def say_greeting(name, greeting):
...     print(f"{greeting}, {name}.")
...
>>> say_greeting("Hello!", "Nina")
Nina, Hello!.

Keyword arguments with default values

Functions can accept two types of named arguments, ones without default values referred to as args, required arguments, positional arguments, or non-default values. Providing values for these are required.

Arguments that have default values are called keyword arguments, kwargs, or optional arguments. The default values you provide can optionally be overwritten.

Let's see this in practice, by writing two functions that print out a greeting. One function will have a default argument to make things easier for us.



Without default arguments

Now, in the REPL, let's try calling our function with no default arguments:

>>> # No Default arguments
>>> say_greeting("Good Day", "Nina")
Good Day, Nina.

Using default arguments

Let's make a new function, say_greeting_with_default that accepts three arguments – name, and now the optional arguments greeting and punctuation. If greeting is not passed in, it will default to Hello, and punctuation will default to !

In the REPL:

>>> # With Default Arguments
>>> def say_greeting_with_default(name, greeting="Hello", punctuation="!"):
...     print(f"{greeting}, {name}{punctuation}")
...
>>> say_greeting_with_default("Nina")
Hello, Nina!
>>> say_greeting_with_default("Nina", "Good Day")
Good Day, Nina!


Order matters!

A function can accept all of one type or the other, but arguments need to go in a specific order.

All of the required arguments go first. They are then followed by the optional keyword arguments.

What happens when we try to define our arguments with keyword arguments defined first? If you guessed a SyntaxError, you're correct!

>>> def say_greeting_bad(greeting="Hello", name):
...     print("Oops, this won't work!")
...
  File "<stdin>", line 1
SyntaxError: non-default argument follows default argument

Calling functions with arguments

There are a few important things to know about calling functions with arguments.

Arguments without defaults are required!

Arguments without default values are required by Python. Otherwise your function wouldn't know what to do! If you don't pass in all the required (positional) arguments, you'll get a TypeError.

>>> def say_greeting(name, greeting):
...     print(f"{greeting}, {name}.")
...
>>> say_greeting("Nina")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: say_greeting() missing 1 required positional argument: 'greeting'

You can pass in none, some, or all of the keyword arguments.

If your function takes keyword arguments, you can provide zero, one, or all of them when you call it. You don't need to pass these arguments in order if you provide their label when calling the function.

>>> def create_query(language="JavaScipt", num_stars=50, sort="desc"):
...     return f"language:{language} num_stars:{num_stars} sort:{sort}"
...
>>> create_query()
'language:JavaScipt num_stars:50 sort:desc'
>>> create_query(language="Ruby")
'language:Ruby num_stars:50 sort:desc'
>>> create_query(num_stars=1, language="Python", sort="asc")
'language:Python num_stars:1 sort:asc'

You can pass in required parameters by keyword.

Even if your function arguments don't have keyword arguments with defaults, you can still pass values in to the function by name. This is especially helpful if you want to be extra clear about what you're passing in.

Note that here, the arguments don't need to be passed to the function in the order that they're defined, because they're labeled.

>>> def say_greeting(name, greeting):
...     print(f"{greeting}, {name}.")
...
>>> say_greeting("Nina", "Hello")
Hello, Nina.
>>> say_greeting(greeting="Bonjour", name="Max")
Bonjour, Max.

Arguments Danger Zone

Warning: Never use mutable types, like lists as a default argument.

Remember to never use an empty list as a default value to a function.

Why? Because it won't work like you'd expect it to.

>>> # Don't do this!
>>> def add_five_to_list(my_list=[]):
...     my_list.append(5)
...     return my_list
...
>>> # This works like we expected it to.
>>> add_five_to_list()
[5]
>>> # Huh?
>>> add_five_to_list()
[5, 5]
>>> # We see that the original `my_list` is still being modified.
>>> add_five_to_list()
[5, 5, 5]

If you need to use a mutable type like a list as a default, use a marker instead. We'll cover this technique later in this chapter.

In Python, default arguments are evaluated only once – when the function is defined. Not each time the function is called. That means if you use a mutable data type like a list as a default argument, it will be reused each time that the function is called.


Naming Functions and Arguments

Because Python is a dynamic language (sometimes called duck-typed) we use names as cues for what our function does, the arguments it accepts, and the values it returns.

This is especially important because we generally don't declare types for our programs when we're first starting out. Note: Python does support Type hinting, but it's more of an intermediate feature. Make sure you have the basics down before learning more about it.

Tip: Try to avoid single character names for your functions and variables, unless they have meaning in math.

For example, in this function, x and y are common names used when referring to points, so it's OK to use single-letter names in this scenario.

def add_points(x1, y1, x2, y2):
    return x1 + x2, y1 + y2
For sequences, like lists, it's appropriate to name them in the plural.

For example, I'd expect a variable called name to be a single string, and a variable called names to be a list of strings.

Tip: A great resource to help you figure out the best naming conventions to use in your production Python code is a talk by Brandon Rhodes, called "The Naming of Ducks: Where Dynamic Types Meet Smart Conventions".


Boolean Logic

Truthiness

Evaluating expressions to be True or False will help us control the flow of our program.

cheat sheet

type truthiness
int 0 is False, all other numbers are True (including negative)
containers - list, tuple, set, dict empty containers evaluate to False, containers with items evaluate to True)
None False

We talked about boolean types (True and False) earlier. True and False are keywords in Python, so make sure you don't name your variables the same thing.
>>> True
True
>>> False
False
Sometimes the truth is obvious. For example 3 < 5 is always True. Other times, in Python, the truth value might surprise you. Let's review. First, let's start with an expression we know is always True.
>>> 3 < 5
True
Tip: If you want to test your assumptions about an expression that returns True or False, you can pass it into the constructor for booleans: bool(expression).


Numbers

In Python, the integer 0 is always False, while every other number, including negative numbers, are True. In fact, under the hood, booleans inherit from integers.

>>> bool(0)
False
>>> bool(1)
True
>>> bool(-1)
True


Sequences

Empty sequences in Python always evaluate to False, including empty strings.
>>> bool("")    # String
False
>>> bool([])    # Empty List
False
>>> bool(set()) # Empty Set
False
>>> bool({})    # Empty Dictionary
False
>>> bool(())    # Empty Tuple
False
Sequences with at least one value will evaluate to True.

>>> bool("Hello")   # String
True
>>> bool([1])       # List
True
>>> bool({1})       # Set
True
>>> bool({1: 1})    # Dictionary
True
>>> bool((1,))      # Tuple
True

None

The None type in Python represents nothing. No returned value. It shouldn't come as a surprise that the truthiness of None is False.
>>> bool(None)
False

None is commonly used as a placeholder to mean "I haven't set this value yet". Since empty strings and sequences evaluate to False, we need to be very careful when we're checking if a sequence has been declared or not, or if it's empty. We'll review this concept again when talking about if statements later in the day.
>>> my_name = None
>>> bool(my_name)
False
>>> my_name = ""
>>> bool(my_name)
False

>>> my_list = None
>>> bool(my_list)
False
>>> my_list = []
>>> bool(my_list)
False

Comparisons

How can we compare different values with each other?

Order Comparisons Cheat Sheet


Operator Means
< less-than
<= less-than-or-equal-to
> greater-than
>= greater-than-or-equal-to

In Python, comparing numbers is pretty straight forward.
>>> 1 < 10  # 1 is less than 10? True
True
>>> 20 <= 20  # 20 is less than or equal to 20? True
True
>>> 10 > 1  # 10 is greater than 1? True
True
>>> -1 > 1  # -1 is greater than 1? False
False
>>> 30 >= 30  # 30 is greater than or equal to 30? True
True

Things get interesting when you try to compare strings. Strings are compared lexicographically. That means by the ASCII value of the character. You don't need to know much about ASCII, besides that capital letters come before lower case ones.

Each character in the two strings is checked one by one, until a character is found that is of a different value. That determines the order. Under the hood, this allows Python to sort strings by comparing them to each other.
>>> "T" < "t"  # Upper case letters are "lower" valued.
True
>>> "a" < "b"
True
>>> "bat" < "cat"
True

Equality Cheat Sheet

Operator Means
== equals
!= not-equals

The equality operators val1 == val2 (val1 equals val2) and val1 != val2 (val1 doesn't equal val2) compare the contents of two different values and return a boolean.

Equality works like you'd expect it to for simple data types.
>>> a = 1
>>> b = 1
>>> a == b
True
>>> a != b
False

>>> a = "Nina"
>>> b = "Nina"
>>> a == b
True
>>> a != b
False

Equality for container types is interesting. Even though a and b are two different lists, their contents are still the same. So compared two lists containing the same values with == will return True.

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a == b
True
>>> a != b
False

Identity Cheat Sheet

Operator Means
is is the same object in memory? (not equality!)
is not is not the same object in memory? (not equality!)

The is keywords tests if the two compared objects are stored in the same memory location. I won't go into too much detail into why, but remember not to use is when what you actually want to check for is equality.

Note: This is something that trips up Python beginners, so make sure you remember that equality (==, !=) is not the same as identity (is, not is).

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]

>>> a ==# Testing for equality. a and b contain the same values
True
>>> a is# Testing for identity. a and b are NOT the same object.
False

Tip: When you're first starting out, the only place you'll want to use the is keyword is to explicitly compare a value to the built-in types of None, True, or False.

>>> a = True
>>> a is True
True

>>> b = False
>>> b is False
True
>>> b is not True   # Opposite of is b True. aka is b False?
True

>>> c = None
>>> c is None
True
>>> c is not None
False

and, or, and not

and, or, and not are the three basic types of boolean operators that are present in math, programming, and database logic.

In other programming languages, you might have seen the concept of and represented with &&, or, represented with ||, and not represented by !. The Python language is instead focused on readability. So we'll use the english and instead of trying to remember fancy symbols. Python still uses the &, | and ! expressions, but they're used for bitwise operations.

You can use them to compare one (or more expressions) and determine if they evaluate to True or False.

Thankfully, you don't have to be a computer scientist to understand them if you use this handy table.

and, or, not Cheat Sheet

Operation Result
a or b if a is False, then b, else a
a and b if a is False, then a, else b
not a if a is False, then True, else False

and

Note: For a and b, if a is false, a is returned. Otherwise b is returned. If a and b are both boolean values, the expression evaluates to True if both a and b are True.

>>> a = True    # a is True
>>> b = True
>>> a and b     # True is returned. (value of b)
True

>>> False and True
False
>>> True and False
False

Notice what happens when do the same thing to values that have a "truthiness" to them.

>>> bool(0) # Verify that zero is "falsey"
False
>>> bool(1) # Verify that one is "truthy"
True
>>> 0 and 1 # 0 is False. 0 is returned.
0

or

For a or b, if a is false, b is returned. If a is true, a is returned. a or b evaluates to True if either (or both) of the expressions are true.

>>> True or True
True
>>> True or False
True
>>> False or False
False

>>> 0 or 1      # 0 is false. Return 1.
1

not

a not a
True False
False True

Note:
not a reverses the boolean value of a. If it was true, it will return False. If it was false, it will return True.

>>> not True
False
>>> not False
True

In Combination

When combining multiple boolean operators, you can add optional parentheses for readability. The operations in the inner-most parenthesis are evaluated first.

>>> a = True
>>> b = True
>>> c = False

>>> a and (b or c)
True
You can combine multiple operators to test complex assumptions. For example, to return True only if both values are False, we can use the not negation operation on the result of an or.

>>> a = False
>>> b = False

>>> a or# False because both are False.
False

>>> not (a or b)  # True - checking if both are False.
True

Control Statements

The if Statement and Conditionals

if in Python means: only run the rest of this code once, if the condition evaluates to True.

Anatomy of an if statement:

  1. Start with the if keyword, followed by a boolean value, an expression that evaluates to True, or a value with "Truthiness".
  2. Add a colon : and a new line
  3. Write the code that will run if the statement is True under a level of indentation

Note: Remember, just like with functions, we know that code is associated with an if statement by it's level of indentation. All the lines indented under the if statement will run if it evaluates to True.

>>> if 3 < 5:
...     print("Hello, World!")
...
Hello, World!

Tip: Remember, your if statements only run if the expression in them evaluates to True and just like with functions, you'll need to enter an extra space in the REPL to run it.


Using not With if Statements

If you only want your code to run if the expression is False, use the not keyword.

>>> b = False
>>> if not b:
...     print("Negation in action!")
...
Negation in action!

if Statements and Truthiness

if statements also work with items that have a “truthiness” to them.

For example:

  • The number 0 is False-y, any other number (including negatives) is Truth-y
  • An empty list, set, tuple or dict is False-y
  • Any of those structures with items in them are Truth-y


>>> message = "Hi there."

>>> a = 0
>>> if a:   # 0 is False-y
...     print(message)
...

>>> b = -1
>>> if b:  # -1 is Truth-y
...     print(message)
...
Hi there.

>>> c = []
>>> if c:  # Empty list is False-y
...     print(message)
...

>>> d = [1, 2, 3]
>>> if d:  # List with items is Truth-y
...     print(message)
...
Hi there.

>>> e = ""
>>> if e:
...     print(message)
...

if Statements and functions

You can easily declare if statements in your functions, you just need to mindful of the level of indentation.

Notice how the code belonging to the if statement is indented at two levels.


>>> def modify_name(name):
...    if len(name) < 5:
...         return name.upper()
...    else:
...         return name.lower()
...
>>> name = "Nina"
>>> modify_name(name)
'NINA'

Nested if Statements

Using the same technique, you can also nest your if statements.

>>> def num_info(num):
...    if num > 0:
...        print("Greater than zero")
...        if num > 10:
...            print("Also greater than 10.")
...
>>> num_info(1)
Greater than zero
>>> num_info(15)
Greater than zero
Also greater than 10.

How not To Use if Statements

Remember, comparisons in Python evaluate to True or False. With conditional statements, we check for that value implicitly. In Python, we do not want to compare to True or False with ==.

Warning - pay attention, because the code below shows what you shouldn't do.

# Warning: Don't do this!
>>> if (3 < 5) is True: # Warning: Don't do this!
...     print("Hello")
...
Hello


Tip: Do this instead:


>>> if 3 < 5:
...     print("Hello")
...
Hello

If we want to explicitly check if the value is explicitly set to True or False, we can use the is keyword.

>>> a = True        # a is set to True
>>> b = [1, 2, 3]   # b is a list with items, is "truthy"
>>>

>>> if a is True:   # we can explicitly check if a is True
...     print("Hello")
...
Hello
>>> if b:  # b is a list with items, is "truthy"
...     print("Hello")
...
Hello
>>> if b is True:   # b does not contain the actual value of True.
...     print("Hello")
...
>>>

else

The else statement is what you want to run if and only if your if statement wasn't triggered.

An else statement is part of an if statement. If your if statement ran, your else statement will never run.

>>> a = True
>>> if a:
...     print("Hello")
... else:
...     print("Goodbye")
...
Hello

And vice-versa.

>>> a = False
>>> if a:
...     print("Hello")
... else:
...     print("Goodbye")
...
Goodbye

In the REPL it must be written on the line after your last line of indented code. In Python code in a file, there can't be any other code between the if and the else.

Info: You'll see SyntaxError: invalid syntax if you try to write an else statement on its own, or put extra code between the if and the else in a Python file.

>>> if a:
...     print("Hello")
...
Hello
>>> else:
  File "<stdin>", line 1
    else:
       ^
SyntaxError: invalid syntax

elif Means Else, If.

elif means else if. It means, if this if statement isn't considered True, try this instead.

You can have as many elif statements in your code as you want. They get evaluated in the order that they're declared until Python finds one that's True. That runs the code defined in that elif, and skips the rest.

>>> a = 5
>>> if a > 10:
...     print("Greater than 10")
... elif a < 10:
...     print("Less than 10")
... elif a < 20:
...     print("Less than 20")
... else:
...     print("Dunno")
...
Less than 10

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 tuples 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'

Practice

Functions

Let's try creating a basic function. Use tab to indent the second line, and press enter on an empty line to finish the function.

>>> def add_numbers(x, y):
...     return x + y
... # Press Enter

Now let's try our new function. Type this into your REPL:
>>> add_numbers(1, 2)
# Let's use the string formatting we learned in the last chapter
>>> print(f"The sum of 1 and 2 is {add_numbers(1, 2)}")


The Importance of Whitespace

Here's an error that you'll become very familiar with during your career as a Pythonista, the IndentationError. Whitespace is important for defining function scope in python, so missing or extra indentations or spaces will cause the runtime to throw this error. Let's redefine our add_numbers function, but we'll forget to indent the second line, return x + y. Notice that the second line is directly under (at the same indentation level) as the def:

>>> def add_numbers(x, y):
... return x + y
  File "<stdin>", line 2
    return x + y
         ^
IndentationError: expected an indented block

Notice how the runtime tells us the line that failed (line 2), gives you a copy of the line with an arrow pointing to the offending error (return x + y), and then tells you the error (IndentationError) with additional information (expected an indented block).


Function Scope

As we saw earlier, scoping in Python happens with whitespace. Let's see this in action:

>>> x = 1
>>> y = 2
>>> def add_numbers(x, y):
...     print(f"Inside the function, x = {x} and y = {y}")
...     return x + y
...
>>> print(f"Outside the function, x = {x} and y = {y}")
>>> print(f"The sum of 5 and 6 is {add_numbers(5, 6)}")


Positional Arguments vs Keyword Arguments

The x and y arguments for our add_numbers() function are called positional arguments. Python also lets us declare keyword arguments. Keyword arguments are great for setting default values, because passing them is optional. Just remember that keyword arguments must come after any positional arguments. Let's make a more generic function for doing math:

>>> def calculate_numbers(x, y, operation="add"):
...     if operation == "add":
...         return x + y
...     elif operation == "subtract":
...         return x - y
...
# Let's try our new function. Remember, if we don't pass the operation keyword argument, the default is "add"
>>> calculate_numbers(2, 3)
# You can pass a keyword argument as a normal positional argument
>>> calculate_numbers(2, 3, "subtract")
# You can also use the argument's keyword. This helps with readability
>>> calculate_numbers(2, 3, operation="subtract")


Boolean Logic

Comparisons

Let's practice using our comparison operators. Remember:

Operator Means
< less-than
<= less-than-or-equal-to
> greater-than
>= greater-than-or-equal-to
== equals
!= not-equals

Remember, the first six operators test the object's value. is and is not test whether two objects are the same thing. This is useful for singletons, such as None or False. We won't be using them much in this intro course, but feel free to play with them.
>>> 10 > 5
>>> 5 > 10
>>> 10 > 10
>>> 10 >= 10
>>> 5 < 10
>>> 5 < 5
>>> 5 <= 5
>>> 5 == 5
>>> 5 != 10


Truthiness

Different languages have different ideas of what is "truthy" and "falsy". In Python, all objects can be tested for truth, and an object is considered True unless except under certain circumstances that we talked about earlier in the chapter. Remember that checking if an object is "equal" to another object doesn't necessarily mean the same thing. An object is considered "truthy" if it satisfies the check performed by if or while statements.

Let's try a few of these out:
>>> 5 == True
>>> # The number 5 does not equal True, but...
>>> if 5:
...     print("The number 5 is truthy!")
...
>>> # The number 5 is truthy for an if test!

True and False can also be represented by 1 and 0
>>> 1 == True
>>> 0 == False


Boolean Operators

Python also supports boolean operators, although they're a little different than the comparison operators. Remember that or and and return one of their operands, rather than True or False.

Operation Result
x or y True if either x or y is True
x and y True if both x and y are True
not x Negates the value of x (i.e. True if x is False)

# Of course, you can use `and` and `or` aren't limited to two operands
>>> a = False
>>> b = False
>>> c = False
>>> a or b or c
>>> b = True
>>> a or b or c

>>> a and b and c
>>> a = True
>>> c = True
>>> a and b and c

>>> a = False
>>> b = False
>>> not a
>>> a and not b


Control statements and looping

if, else, and elif

Let's practice our branching statements. Remember that elif (short for else if) is an optional branch that will let you add another if test, and else is an optional branch that will catch anything not previously caught by if or elif.
>>> def test_number(number):
...     if number < 100:
...         print("This is a pretty small number")
...     elif number == 100:
...         print("This number is alright")
...     else:
...         print("This number is huge!")
...
>>> test_number(5)
>>> test_number(99)
>>> test_number(100)
>>> test_number(8675309)

You can also have multiple conditions in an if statement. This function prints "Fizzbuzz!" if the number is divisible by both 3 and 5 (the % or modulo operator returns the remainder from the division of two numbers):

>>> def fizzbuzz(number):
...     if number % 3 == 0 and number % 5 == 0:
...         print("Fizzbuzz!")
...
>>> fizzbuzz(3)
>>> fizzbuzz(5)
>>> fizzbuzz(15)

Let's also practice using if to test for an empty list. Remember that an empty list is "Falsey", or resolves to False. Write a function to print a list of elements, or an error message if the list is empty. Print a special message if a list item is None:

>>> def my_func(my_list):
...     if my_list:
...         for item in my_list:
...             if item is None:
...                 print("Got None!")
...             else:
...                 print(item)
...     else:
...         print("Got an empty list!")
...
>>> my_func([1, 2, 3])
>>> my_func([2, None, "hello", 42])
>>> my_func([])



The for loop, range() and enumerate()

Let's try making a list and looping over it:

>>> my_list = [0, 1, 2]
>>> for num in my_list:
...     print(f"Next value: {num}")
...

If we're just interested in looping over a list of numbers, we can use the range() function instead. Remember that the first argument is inclusive and the second is exclusive:

>>> for num in range(0, 3):
...     print(f"Next value: {num}")
...

Another useful function is enumerate(), which iterates over an iterable (like a list) and also gives you an automatic counter. enumerate() returns a tuple in the form of (counter, item).

>>> my_list = ["foo", "bar", "baz"]
>>> for index, item in enumerate(my_list):
...     print(f"Item {index}: {item}")
...

We can also loop over a dictionary's keys and/or values. If you try to iterate over the dictionary object itself, what do you get?

>>> my_dict = {"foo": "bar", "hello": "world"}
>>> for key in my_dict:
...     print(f"Key: {key}")
...
# This is equivalent to...
>>> for key in my_dict.keys():
...     print(f"Key: {key}")
...

The keys() method returns the dictionary's keys as a list, which you can then iterate over as you would any other list. This also works for values()

>>> for value in my_dict.values():
...     print(f"Value: {value}")
...

The most useful function, however, is items(), which returns the dictionary's items as tuples in the form of (key, value):

>>> for key, value in my_dict.items():
...     print(f"Item {key} = {value}")
...


return

You can use the return keyword to break out of a loop within a function, while optionally returning a value.

>>> def is_number_in_list(number_to_check, list_to_search):
...     for num in list_to_search:
...         print(f"Checking {num}...")
...         if num == number_to_check:
...             return True
...     return False
...
>>> my_list = [1, 2, 3, 4, 5]
>>> is_number_in_list(27, my_list)
>>> is_number_in_list(2, my_list)

Notice that our function is_number_in_list checks all the numbers in my_list on the first run, but on the next run, stops immediately when it hits 3 and returns True.

while loop

Instead of looping over a sequence, while loops continue looping while a certain condition is met (or not met). The condition is checked at the beginning of every iteration.

>>> counter = 0
>>> while counter < 3:
...     print(f"Counter = {counter}")
...     counter += 1
...

Notice that the loop ends once counter == 3, and the remainder of the loop is bypassed. You can also loop forever by using while True or while False, but you should make sure you have solid break conditions, or your program will just loop forever (unless that's what you want).

>>> counter = 0
>>> while True:
...     print(f"Counter = {counter}")
...     if counter == 3:
...         break
...     counter += 1
...


Nested Loops

Nesting loops is often necessary and sometimes tricky. The break keyword will only get you out of whichever loop you're breaking. The only way to exit all loops is with multiple break statements (at each level), or the return keyword (inside a function). For example:

names = ["Rose", "Max", "Nina"]
target_letter = 'x'
found = False

for name in names:
    for char in name:
            if char == target_letter:
                    found = True
                    break

    if found:
        print(f"Found {name} with letter: {target_letter}")
        break

Or:

>>> for x in range(0, 5):
...     for y in range(0, 5):
...         print(f"x = {x}, y = {y}")
...         if y == 2:
...             break
...

Notice how the inner y loop never gets above 2, whereas the outer x loop continues until the end of its range.

Solutions

Functions

Here's what you should have seen in your REPL:

>>> add_numbers(1, 2)
3
# Let's use the string formatting we learned in the last chapter
>>> print(f"The sum of 1 and 2 is {add_numbers(1, 2)}")
The sum of 1 and 2 is 3


Function Scope

Here's what you should have seen in your REPL:

>>> x = 1
>>> y = 2
>>> def add_numbers(x, y):
...     print(f"Inside the function, x = {x} and y = {y}")
...     return x + y
...
>>> print(f"Outside the function, x = {x} and y = {y}")
Outside the function, x = 1 and y = 2
>>>
>>> print(f"The sum of 5 and 6 is {add_numbers(5, 6)}")
Inside the function, x = 5 and y = 6
The sum of 5 and 6 is 11


Positional Arguments vs Keyword Arguments

Here's what you should have seen in your REPL:

>>> def calculate_numbers(x, y, operation="add"):
...     if operation == "add":
...         return x + y
...     elif operation == "subtract":
...         return x - y
...
# Let's try our new function. Remember, if we don't pass the operation keyword argument, the default is "add"
>>> calculate_numbers(2, 3)
5
# You can pass a keyword argument as a normal positional argument
>>> calculate_numbers(2, 3, "subtract")
-1
# You can also use the argument's keyword. This helps with readability
>>> calculate_numbers(2, 3, operation="subtract")
-1


Boolean Logic

Comparisons

Here's what you should have seen in your REPL:


>>> 10 > 5
True
>>> 5 > 10
False
>>> 10 > 10
False
>>> 10 >= 10
True
>>> 5 < 10
True
>>> 5 < 5
False
>>> 5 <= 5
True
>>> 5 == 5
True
>>> 5 != 10
True

Truthiness

Here's what you should have seen in your REPL:

>>> 5 == True
False
>>> # The number 5 does not equal True, but...
>>> if 5:
...     print("The number 5 is truthy!")
...
The number 5 is truthy!
>>> # The number 5 is truthy for an if test!

>>> 1 == True
True
>>> 0 == False
True


Boolean Operators

Here's what you should have seen in your REPL:

>>> a = False
>>> b = False
>>> c = False
>>> a or b or c
False
>>> b = True
>>> a or b or c
True

>>> a and b and c
False
>>> a = True
>>> c = True
>>> a and b and c
True

>>> a = False
>>> b = False
>>> not a
True
>>> a and not b
False

Control statements and looping

if, else, and elif

Here's what you should have seen in your REPL:

>>> def test_number(number):
...     if number < 100:
...         print("This is a pretty small number")
...     elif number == 100:
...         print("This number is alright")
...     else:
...         print("This number is huge!")
...
>>> test_number(5)
This is a pretty small number
>>> test_number(99)
This is a pretty small number
>>> test_number(100)
This number is alright
>>> test_number(8675309)
This number is huge!

>>> def fizzbuzz(number):
...     if number % 3 == 0 and number % 5 == 0:
...         print("Fizzbuzz!")
...
>>> fizzbuzz(3)
>>> fizzbuzz(5)
>>> fizzbuzz(15)
Fizzbuzz!

>>> def my_func(my_list):
...     if my_list:
...         for item in my_list:
...             if item is None:
...                 print("Got None!")
...             else:
...                 print(item)
...     else:
...         print("Got an empty list!")
...
>>> my_func([1, 2, 3])
1
2
3
>>> my_func([2, None, "hello", 42])
2
Got None!
hello
42
>>> my_func([])
Got an empty list!


The for loop, range() and enumerate()

Here's what you should have seen in your REPL:

>>> my_list = [1, 2, 3]
>>> for num in my_list:
...     print(f"Next value: {num}")
...
Next value: 0
Next value: 1
Next value: 2

>>> for num in range(0, 3):
...     print(f"Next value: {num}")
...
Next value: 0
Next value: 1
Next value: 2

>>> my_list = ["foo", "bar", "baz"]
>>> for index, item in enumerate(my_list):
...     print(f"Item {index}: {item}")
...
Item 0: foo
Item 1: bar
Item 2: baz

>>> my_dict = {"foo": "bar", "hello": "world"}
>>> for key in my_dict:
...     print(f"Key: {key}")
...
Key: foo
Key: hello

>>> for key in my_dict.keys():
...     print(f"Key: {key}")
...
Key: foo
Key: hello

>>> for value in my_dict.values():
...     print(f"Value: {value}")
...
Value: bar
Value: world

>>> for key, value in my_dict.items():
...     print(f"Item {key} = {value}")
...
Item foo = bar
Item hello = world

return

Here's what you should have seen in your REPL:


>>> def is_number_in_list(number_to_check, list_to_search):
...     for num in list_to_search:
...         print(f"Checking {num}...")
...         if num == number_to_check:
...             return True
...     return False
...
>>> is_number_in_list(27, my_list)
Checking 1...
Checking 2...
Checking 3...
Checking 4...
Checking 5...
False
>>> is_number_in_list(2, my_list)
Checking 1...
Checking 2...
True

while loop

Here's what you should have seen in your REPL:

>>> counter = 0
>>> while counter < 3:
...     print(f"Counter = {counter}")
...     counter += 1
...
Counter = 0
Counter = 1
Counter = 2

>>> counter = 0
>>> while True:
...     print(f"Counter = {counter}")
...     if counter == 3:
...         break
...     counter += 1
...
Counter = 0
Counter = 1
Counter = 2
Counter = 3

Nested Loops

Here's what you should have seen in your REPL:

>>> for x in range(0, 5):
...     for y in range(0, 5):
...         print(f"x = {x}, y = {y}")
...         if y == 2:
...             break
...
x = 0, y = 0
x = 0, y = 1
x = 0, y = 2
x = 1, y = 0
x = 1, y = 1
x = 1, y = 2
x = 2, y = 0
x = 2, y = 1
x = 2, y = 2
x = 3, y = 0
x = 3, y = 1
x = 3, y = 2
x = 4, y = 0
x = 4, y = 1
x = 4, y = 2

Break & Continue

break and continue allow you to control the flow of your loops. They're a concept that beginners to Python tend to misunderstand.

Using break

The break statement will completely break out of the current loop, meaning it won't run any more of the statements contained inside of it.

>>> names = ["Rose", "Max", "Nina", "Phillip"]
>>> for name in names:
...     print(f"Hello, {name}")
...     if name == "Nina":
...         break
...
Hello, Rose
Hello, Max
Hello, Nina

Tip: break completely breaks out of the loop.


Using continue

continue works a little differently. Instead, it goes back to the start of the loop, skipping over any other statements contained within the loop.

>>> for name in names:
...     if name != "Nina":
...         continue
...     print(f"Hello, {name}")
...
Hello, Nina

Tip: continue continues to the start of the loop


break and continue visualized

What happens when we run the code from this Python file?

# Python file names.py
names = ["Jimmy", "Rose", "Max", "Nina", "Phillip"]

for name in names:
    if len(name) != 4:
        continue

    print(f"Hello, {name}")

    if name == "Nina":
        break

print("Done!")

break and continue visualized


Results

See if you can guess the results before expanding this section.

(env) $ python names.py

Hello, Rose
Hello, Nina
Done!

Using break and continue in nested loops.

Remember, break and continue only work for the current loop. Even though I've been programming Python for years, this is something that still trips me up!


>>> names = ["Rose", "Max", "Nina"]
>>> target_letter = 'x'
>>> for name in names:
...     print(f"{name} in outer loop")
...     for char in name:
...             if char == target_letter:
...                 print(f"Found {name} with letter: {target_letter}")
...                 print("breaking out of inner loop")
...                 break
...
Rose in outer loop
Max in outer loop
Found Max with letter: x
breaking out of inner loop
Nina in outer loop
>>>

Tip: break in the inner loop only breaks out of the inner loop! The outer loop continues to run.


Loop Control in while loops

You can also use break and continue in while loops. One common scenario is running a loop forever, until a certain condition is met.

>>> count = 0 
>>> while True:
...     count += 1
...     if count == 5:
...             print("Count reached")
...             break
...
Count reached

Note: Be careful that your condition will eventually be met, or else your program will get stuck in an infinite loop. For production use, it's better to use asynchronous programming.