Intro to Python Day 2: Flow Control and New Data Types

Reminders

  • Office hours from 10-12, or by appointment

    • I know that many of you are in the Math Lecture (and likely also the LaTex lecture). If you want to meet via zoom at some other time, email me.
  • Optional readings are posted on the syllabus

  • Practice is key!

Course Outline

  • Yesterday: Intro and Coding Basics

  • Today: Basics Continued and Control Flow

  • Wednesday: Object Oriented Programming and Functions

  • Thursday: Data Analysis and APIs

  • Friday: Web Scraping and Text-as-Data

Python Syntax is Sensitive!

At the end of class, we tried the following code which seemed to work in colab.

Day = input("What day is it?")

if Day == "Friday" or "friday":
    print("It's Friday, I'm in love!")

It seemed like it worked well! But, let’s check it out in Colab…

Let’s Review

Create an object radius, with value 10. Create a second object, pi, with value 3.14.

Create a third object, circumference, that uses the first two objects to calculate the circumference of a circle with the above values. Look it up if you don’t know the formula.

Quick Recall

Recall the comparison operators from yesterday (<, <=, >, >=, ==, !=).

Sanity check: what does 5 == 5.0 return?

Boolean Review

Write a script that prints Hi <your name> if name == "<your name>".

Test it by assigning your actual name to name, then changing it to something else.

Logical Operators on Booleans

  • not, or, and are logical operators

    • Note: | and & work elementwise on NumPy and pandas arrays — don’t use them for simple boolean logic. Stick with or and and.
  • not a is true if a is False, False if a is True

  • a or b is true if at least one of a or b is true

  • a and b is true only if both a and b are true

Logical Operator Example

# How did you get to work today
bike = True
bus = False

print(not bus)

What will this print?

print(bus or bike)

What about this?

print(bus and bike)

Control Flow

If is used to evaluate an expression if a condition is true

if <condition>:
    <expression 1>
    <expression 2>
  
some other code

If statements are always <condition>:

Don’t forget the colon.

Indentation can be any consistent amount of spaces, but 4 is the convention.

Everything within the indentation is evaluated conditionally. Once you remove indentation, everything is evaluated.

Graphical if control flow

Flowchart of if/else logic: a diamond decision node tests the condition; True branches to action B; False branches to action C.

Note that if the condition is not met, the code just ignores the if statement and continues on.

Budgeting Example

earned = int(input('How much money did you earn? '))
spent = int(input('How much money did you spend? '))
if earned > spent:
    print('Great! You earned more than you spent. Good job.')

The script compares earned to spent, and if we earned more than we spent, it congratulates us.

Try a poli sci version: write a script that prints A wins! if candidate A got more votes than candidate B.

Multiple Conditionals

One way to add some complexity is to have sequential if statements. For example, imagine we wanted different responses if the user had a surplus, a deficit, or was breaking even.

How could we write such a script using three sequential if statements?

Branching

An if statement is performed when a condition is true. What if we also want to specify what happens if the condition is false?

else statements are used with if statements, such that the if statement is only executed if the condition is true, and the else statement is only executed if the condition is false.

What are some potential examples of when we could use an else statement?

Else Statements Graphically

Flowchart of if/else logic with both branches: a diamond decision tests the condition; True branches to action B; False branches to action C; both paths rejoin afterward.

How is this different than the logic of a simple if statement?

Else Statement Code Example

Imagine we wanted to write code to determine whether someone is eligible to vote, based on their age.

We could use two if statements, but more commonly we will use an if statement followed by an else statement. What would that look like?

Nesting Statements

We can “nest” conditional statements inside of other conditionals, using the following format

if condition:
    if condition:
        code
else:
    code

Imagine now that voting requires both being old enough and being registered. We can nest a second if statement, evaluated only when the first one is true, to handle this. What would the code look like?

Elif Statements

If/else statements cover the set of cases where you have code you want to execute if condition a is true, and other code to execute if condition a is false. What if you have a more complex situation based on multiple conditions?

Imagine a polling place reviews voter check-ins. If the voter is registered at this precinct, allow them to vote. Else if they are at the wrong precinct, redirect them. Otherwise, offer a provisional ballot.

Elif Graphical Intuition

Flowchart of if/elif/else logic: a chain of diamond decision nodes, each testing a condition; the first True branch executes its code; if no condition matches, the final else branch runs.

Now we can have fairly complicated conditions, each with their own code to execute.

You Try

Write a script that tells a student what course in a methods sequence they should register for. Ask them for an input which represents their current knowledge level.

If the student has no prior knowledge, they should take “Quant 1”. If they have a little prior knowledge, they should take “Quant 2”. If they are already advanced, they should sign up for “Quant 3”.

We can keep making things more complicated!

Flowchart of nested if statements: an outer diamond decision node branches True into a second inner diamond, which itself branches into two further actions; the outer False branch leads to a separate action.

A More Complicated Problem

Let’s ask users what the weather is like, and give feedback based on the answer.

If the weather is rainy, tell the user to grab an umbrella. If it’s sunny, tell them to grab some shades. Otherwise, if it’s cloudy, ask them if the weather is cold or not. If it’s cold, tell them to put a coat on, if it’s not, tell them a long sleeve shirt should be fine.

Finally, if they give some other answer, tell them to just wear something comfy.

Break

Parsing Nested Statements

How do we know when code will be evaluated?

How do we know which else belongs to which if?

Indentation!

# number = some numeric value

if number % 2 == 0:  # if number divided by two leaves no remainder
    print("Number is even.")
    if number % 3 == 0:
        print("Number is divisible by 6.")
    else:
        print("Number is not divisible by 6.")
else:
    print("Number is odd.")

Loops

  • What if you want to repeat a task many times? There are often many ways to do this.

    • In R you have the apply functions, or you can map if you are a tidyverse user
  • In python there are also plenty of different ways, but loops are a very common approach

  • There are two types of common loops you will see, for loops and while loops

Loops: While

Keeps running while a condition is true.

while <condition>:
    <expression>
    <expression>

The loop will keep running until the condition is no longer true, then exit.

Warning: It’s possible to write infinite loops that never exit, often by accident. We want to avoid this by paying close attention to our condition.

While Loop Example

# program to display the numbers from 1 to 5

i = 1  # initialize the condition
n = 5

# while loop from i = 1 to 5
while i <= n:
    print(i)
    i = i + 1  # this will update the condition
1
2
3
4
5

Common Syntax for While Loops

index = 0  # Declare an index variable
while index < 10:  # compare index value to condition
    print("hi")  # the code to be executed
    index += 1  # update the index

Graphical While Loops

Flowchart of a while loop: a diamond decision node tests the condition; True executes the loop body and loops back to the condition; False exits the loop.

You Try

Write a script to find the smallest number greater than 700 that is divisible by 13, using a while loop.

Hint - The standard set up for a while loop will work well here, you just need to think about what the right starting index is. Also, recall the modulo operator %!

A Solution

number = 701 # start at the first number greater than 700

while number % 13 != 0:
    print(f"{number} is not divisible by 13.") ## remember those f strings from earlier!
    number += 1
print(f"{number} the smallest number greater than 700 and divisible by 13")
701 is not divisible by 13.
702 the smallest number greater than 700 and divisible by 13

Nested While Loop

# A list of names
names = ["Alice", "Bob", "Charlie"]

# A list of languages to greet in
languages = ["English", "Spanish", "French"]

# Outer loop: step through each person
i = 0
while i < len(names):
    name = names[i]

    # Inner loop: for the current person, greet in each language
    j = 0
    while j < len(languages):
        lang = languages[j]
        if lang == "English":
            greeting = "Hello"
        elif lang == "Spanish":
            greeting = "¡Hola"
        elif lang == "French":
            greeting = "Bonjour"
        else:
            greeting = "Hi"

        print(f"{greeting}, {name}!")
        j += 1

    # Move to the next person
    i += 1

Graphical Nested While Loops

Flowchart of a nested while loop: an outer condition diamond branches True into an inner condition diamond; the inner True executes the inner body and loops back; the inner False returns to the outer body, which then loops back to the outer condition; the outer False exits.

Another One

What will this code do?

n = 1
while n <= 50:
    count = 0
    m = n
    while m % 13 != 0:
        count += 1
        m += 1
    print(f"{n} reaches a multiple of 13 ({m}) after {count} steps.")
    n += 1

You Try

Create the following object

sentence = 'There once lived a bee in a house by the sea.'

Write a nested while loop that prints each 10 character sequence in the sentence, so that the output looks like

There once

here once

ere once l

and so on

Hint: Write the inner loop (i.e., the basic loop to print the first 10 characters) first, then nest it.

For Loops

With for loops, you explicitly define the range over which the loop will execute.

Similar to while loops, but when you know the number of iterations, the syntax is cleaner. Each iteration, the running variable updates its value (it iterates over the iterable object) — no manual index updates needed.

for <variable> in <iterable>:
    <expression>

Most commonly we iterate over a numeric range, but we can also iterate over items in a list, dictionary, tuple, set, etc.

for <numeric> in range(<some_numeric>):
    <expression>

Notes on Range()

range(start, stop, step)
  • By default, start = 0 and step = 1

  • Only stop is required, start and step are optional

  • Will loop from start until stop - 1

Examples

How will these evaluate?

for i in range(1, 5):
    print(i)

for i in range(11, 15, 1):
    print(i)

for i in range(1, 30, 5):
    print(i)

A more complex for loop

words = ["apple", "bat", "bar", "atom", "book"]

by_letter = {}

for word in words:
    letter = word[0]
    if letter not in by_letter:
        by_letter[letter] = [word]
    else:
        by_letter[letter].append(word)

print(by_letter)

What will this code do?

You Try

Write a for loop that loops over all the characters in “Michigan” and outputs each character individually followed by a !.

for char in "CLEMSON":
    print(char + "!")
C!
L!
E!
M!
S!
O!
N!

Break Statements

  • Sometimes, you might want the loop to stop early if some predefined conditions are met

  • Break statements do exactly this, exiting the loop and stopping evaluation

for i in range(1, 4):
    for j in range(1, 4):
        if i == 2 and j == 2:
            break  # break will only exit the inner loop
    print(i, j)  # why is this the output we get?
1 3
2 2
3 3

You Try

Write a for loop that runs 4 times. On each iteration, prompt the user for a word, then print the first and last letter of that word.

Let’s take a Break

Lists

  • Lists are one of the four basic data types in which to store values in Python

    • The others are tuples, dictionaries and sets.

    • NumPy, Pandas, etc will add more types (like how the tidyverse adds tibble in R)

      • Arrays and DataFrames will be familiar to R users (or spreadsheet users)
  • Used to store multiple items in a single variable

    my_fav_fruits = ["Peaches", "Raspberries", "Blueberries", "Mangoes"]

More on lists

Items in a list don’t all need to be of the same type

my_list = ["cactus", 42, False]
my_list
['cactus', 42, False]

You can also initialize empty lists, and fill them as you go

empty_list = []

Ordering

Lists are ordered, which means you can access an item with its index

Warning

Remember, python indexes start at 0, not 1!

fruits = ["Papaya", "Passion Fruit", "Pineapple", "Pomegranate"]

fruits[0]
'Papaya'

Remember, we can also use negative indexing to start from the end

fruits[-1]
'Pomegranate'

Lists can have duplicates

An item can occur more than once in a list

fruit = ["apple", "apple", "pear", "plum"]

sets can only contain each object a single time

Lists are mutable

  • Lists are mutable objects

  • This means that they can be modified in place

fruit[2] = "cherry"

print(fruit)
['apple', 'apple', 'cherry', 'plum']

Length Function

Sometimes, it’s useful to know the length of a list. The length of a list is the number of elements in the list, rather than say the total number of characters in the list. The len() function will find the length for us.

len(fruit)
4

Methods

  • len() was a function that we called on a list.

  • methods are functions that belong to a specific object

    • only work with that object
  • syntax: object.method()

    • For R users, this is a big difference

    • Extra confusing because function(object) is also still valid python syntax!

List methods

  • append

  • insert

  • reverse

  • sort

  • index

  • extend

  • etc, etc

append()

append() adds an item to the end of a list

teams = ["Red Sox", "Braves", "Cubs"]
teams.append("Giants")
print(teams)
['Red Sox', 'Braves', 'Cubs', 'Giants']

Note that we don’t have to do any reassignment or use any indexing. The list is modified by append() and updated in memory

Insert()

insert() adds an element at a specified position. The syntax is

list.insert(index, element)

Use the insert() method to insert the “Phillies” into this list, with index = 1.

Notice how this is different than updating an index

teams[1] = "Rays"

print(teams)
['Red Sox', 'Rays', 'Cubs', 'Giants']

Sort

sort() will order your list. The default is to sort in ascending order

teams.sort()
print(teams)
['Cubs', 'Giants', 'Rays', 'Red Sox']

But we can also sort in descending order by using reverse

teams.sort(reverse=True)
print(teams)
['Red Sox', 'Rays', 'Giants', 'Cubs']

Or even by length using key

teams = ["Red Sox", "Braves", "Cubs"]
teams.sort(key=len)
print(teams)
['Cubs', 'Braves', 'Red Sox']

Sorted()

To see the difference between using a function and a method, consider the function sorted

sorted(object) returns a sorted version of the list, without updating the original

teams = ["Red Sox", "Braves", "Cubs"]
print(sorted(teams))
print(teams)
['Braves', 'Cubs', 'Red Sox']
['Red Sox', 'Braves', 'Cubs']

Index

Index returns the index of the first element with the specified value

teams.index("Red Sox")
0

extend()

extend() adds the elements of a new list (or other iterable) to an existing list

new_teams = ["Blue Jays", "Orioles", "Cardinals"]

teams.extend(new_teams)

print(teams)
['Red Sox', 'Braves', 'Cubs', 'Blue Jays', 'Orioles', 'Cardinals']

Remove and Pop

Remove removes a named element

teams.remove("Cubs")
print(teams)
['Red Sox', 'Braves', 'Blue Jays', 'Orioles', 'Cardinals']

pop removes by index and returns the element that has been deleted

teams.pop(1) 
print(teams)
['Red Sox', 'Blue Jays', 'Orioles', 'Cardinals']

If you don’t give an index, pop removes the last element in the list

Indexing and Slicing

We can slice lists using the [start:stop:step] syntax that we saw with range earlier

  • start at start (default 0)

  • stop one step before stop (default is len(list))

  • step specifies how many indices to jump

teams[:2]    # first two elements
['Red Sox', 'Blue Jays']
teams[1:]    # everything from index 1 onward
['Blue Jays', 'Orioles', 'Cardinals']
teams[::2]   # every other element
['Red Sox', 'Orioles']

Your Turn

  • Create a list of at least 4 objects of your choice.

  • Add an object as the third item of your list

  • Create a second list of at least two objects and add it to the first.

  • Remove the second item on your list.

  • Sort your list alphabetically.

  • Using slicing, only keep the last three items in your list

Combining Lists and Loops

Consider the following list:

fruits = ["apple", "banana", "cherry", "pineapple", "kiwi"]

How could we write a for loop to return all of the fruits in the list? What about a while loop?

Combining Lists, Loops and Conditionals

Suppose we wanted to designate some fruits as short-name fruits and some fruits as long-name fruits, based on how many letters they have. Write a loop that assigns fruits with less than six letters to a list called short_fruit and fruits with six or more letters to a list called long_fruit. Check that the loop does what you expect by printing each list.

String Methods

  • startswith()

  • endswith()

  • capitalize() uppercases the first character and lowercases the rest

  • title() capitalizes the first character of every word

  • upper() capitalizes everything

  • lower() converts everything to lower case

Tuples

  • Tuples are also ordered sequences of items

  • Unlike lists, they are immutable (cannot be changed on the fly)

  • Created with parentheses ()

tpl = ("a", True, 5, "Red Sox")
print(tpl)

tpl[3] = "Blue" ## Note that this causes an error message, because the tuple is immutable
('a', True, 5, 'Red Sox')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[28], line 4
      1 tpl = ("a", True, 5, "Red Sox")
      2 print(tpl)
----> 4 tpl[3] = "Blue" ## Note that this causes an error message, because the tuple is immutable

TypeError: 'tuple' object does not support item assignment

Why Tuples?

  • Aren’t these just slightly less useful lists?

  • Sometimes, immutability is an advantage. More stable, safer if you know you want the values to stay constant

    • More computationally efficient
  • Useful for use as keys in a dictionary (more soon)

Methods for Tuples

  • Since tuples are immutable, they only have two methods

    • count()

    • index()

tpl = ("a", "b", "a")

print(tpl.count("a"))
print(tpl.index("b"))
2
1

Sets

  • Sets are unordered collections of items

  • Sets store unique elements, with no duplicates

  • Uses hashing for efficient storage/retrieval

    • computationally efficient, great for quick look-up
  • Sets are generally created with curly braces

  • Empty sets are created with set()

my_set = {14, "a", 5, True, 11}
my_empty_set = set()

Using Sets for Quick Lookup

  • Create a set of voters who have already cast a ballot

  • Check to see if Will is among them

voted = {"Will", "Sarah", "John", "Amy"}

"Will" in voted
True

Sets v Lists

  • Sets:

    • Use hashing — go directly to where the item should be stored, regardless of set size
  • Lists:

    • Scan elements one by one — slow for big lists
  • Sets are more computationally efficient; lists are more flexible

Set Operations

  • .add() adds an element to a set

  • .union() will return the union of two sets

  • .update() will return the union and update the original

  • .difference() will return the difference between two sets

  • .difference_update() will modify the original set

s = {"John", "Jack"}
s.add("Chuck")
print(s)
{'John', 'Jack', 'Chuck'}
s_new = {"Sarah", "Tara", "Jack"}

s.union(s_new)
{'Chuck', 'Jack', 'John', 'Sarah', 'Tara'}
s.difference(s_new)
{'Chuck', 'John'}

You Try

  • Create a list of newspaper titles

  • Iterate over the list to make all of the titles lowercase

  • Create a second list of TV News networks

  • Add the elements of the new list to the old list

An Answer

papers = ["New York Times", "Washington Post", "Boston Globe", "Philadelphia Inquirer", "Atlanta Journal-Constitution"]

for i in range(len(papers)):
    papers[i] = papers[i].lower()
papers
['new york times',
 'washington post',
 'boston globe',
 'philadelphia inquirer',
 'atlanta journal-constitution']
stations = ["Fox News", "CNN", "MSNBC", "Newsmax"]
papers.extend(stations)
papers
['new york times',
 'washington post',
 'boston globe',
 'philadelphia inquirer',
 'atlanta journal-constitution',
 'Fox News',
 'CNN',
 'MSNBC',
 'Newsmax']

See You Tomorrow!

  • Tomorrow — Functions, Modules, and NumPy

  • Questions: come to office hours (10 AM – 12 PM daily), or email me

  • Recommended reading: OpenStax Introduction to Python Programming, Ch. 4–5, 9–10

  • Slides will be posted after class on Canvas and at will-horne.github.io/icpsr-2026