# Outside any section
if True:
...
# Inside a section
# See? It's indented!
# Outside any sectionMore Control Flow Tools (Part I)
Today, we’re discussing sections 4.1-4.7 of The Python Tutorial. These are
- 4.1
ifStatements - 4.2
forStatements - 4.3 The
range()Function - 4.4
breakandcontinueStatements - 4.5
elseClauses on Loops - 4.6
passStatements - 4.7
matchStatements
Next month, we’ll cover 4.8-4.9: Functions
Intro
The goal of this section is to control how we run certain sections of code.
In Python, you create a section of code by indenting it:
4.1 if Statements
Conditionals: for running (indented) code only under certain conditions
if: always necessaryelif: optional, additional conditions (only if the previous fail)else: optional, catches anything that fails
# Just a single if
i_feel = "happy"
if i_feel == "happy":
print("I feel happy")I feel happy
# if-elif-else
i_feel = "happy"
if i_feel == "happy":
print("I feel happy")
elif i_feel == "unhappy":
print("I feel unhappy")
else:
print("I don't feel happy or unhappy")I feel happy
4.2 for Statements
for statements let you run an indented block multiple times, once for each element in an iterable (something with multiple elements, like a list).
# Measure some strings:
words = ['cat', 'window', 'defenestrate']
for w in words:
print(w, len(w))cat 3
window 6
defenestrate 12
It’s possible to modify the iterable during the list. This can make things unpredictable, don’t do it. If you have to, use a copy of the object.
# Measure some strings:
words = ['cat', 'window', 'defenestrate']
for w in words.copy():
print(w, len(w))
words.append(w)
print(words)cat 3
window 6
defenestrate 12
['cat', 'window', 'defenestrate', 'cat', 'window', 'defenestrate']
4.3 The range() Function
It’s common to loop over a range of numbers. The range() function makes that simpler. It represents a list of integers from start to stop every step:
# default start=0 and step=1
range(stop)
# default step=1
range(start, stop)
# with everything specified
range(start, stop, step)
for i in range(-10, 10, 2):
print(i)-10
-8
-6
-4
-2
0
2
4
6
8
range() objects have some weird properties
startis included butstopis excluded- You can use functions like
sum()to add up the range - They don’t store all the numbers at once (makes them very efficient but you can’t index/subset them like lists. More on this next month)
4.4 break and continue Statements
Helper statements for loops.
break exits the loop:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
breakapple
continue skips to the start of the next iteration. These are both useful in conjunction with conditionals:
for fruit in fruits:
if fruit == "banana":
print("yuck!")
continue
print(fruit)apple
yuck!
cherry
4.5 else Clauses on Loops
This is an odd but useful one. 99% of the time else statements are in if blocks and catch anything that fails the conditions.
When else follows a loop, it catches anything that didn’t break out of the loop. If the loop ends without break, the else condition will run.
Let’s see where this is useful:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
if fruit == "banana":
print("yuck! I hate bananas.")
break
# else connected to for loop, not if statement (compare indentation)
else:
print("Phew! no bananas")yuck! I hate bananas.
They also work for while loops. Remember them? They’re like conditionals+loops combined, they run an indented block until a condition is false.
4.6 pass Statements
These are simpler - pass statements do nothing. Nothing at all!
passif "banana" in fruits:
passfor fruit in fruits:
passWhy have them then? Because empty indented blocks throw an error:
if "banana" in fruits:
# do this laterCell In[56], line 2 # do this later ^ SyntaxError: incomplete input
With pass, we can set up the framework but leave the implementation for later.
if "banana" in fruits:
pass # do this later4.7 match Statements
These are for pattern matching, and are the most advanced feature we’ll look at today. You don’t need to use these - an if stack can always do the job. But it’s useful and can be quick.
You match something to a case (usually multiple):
match something:
case possibility_1:
# some code
case possibility_2:
# some code
A ‘possibility’ of _ will match anything (it’s a wildcard). Cases are checked in order and only one is matched.
status = 418
match status:
case 400:
print("Bad request")
case 404:
print("Not found")
case 418:
print("I'm a teapot")
case _:
print("Something's wrong with the internet")I'm a teapot
Combine several options with vertical bar | (“or”)
status = 401
match status:
case 400:
print("Bad request")
case 401 | 403 | 404:
print("Not allowed")
case 404:
print("Not found")
case 418:
print("I'm a teapot")
case _:
print("Something's wrong with the internet")Not allowed
So far so good. It gets weird though. You can implicitly assign to variables if you put them in the patterns!
point = (3, 4)
match point:
case (x, y):
print(x, y)3 4
This magically created the variables x and y and assigned their values!
A more complex example is given in The Python Tutorial
point = (3, 4)
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
print("Not a point!")X=3, Y=4
Lastly: guards. Let’s say the pattern matches but you still want to exclude specific cases. Use if to do this:
point = (3, 4)
match point:
case (x,y) if x == y:
print(f"Y=X at {x}")
case (x, y):
print(f"Not on the diagonal")Not on the diagonal