if statement: a body of code that is executed based on a conditionAlmost as fundamental to programming as the function, if statements let us make our programs smarter. They let code do different things based on a conditional expression. In this chapter, we go into the many ways that if statements can be used to control the flow of the program. We see not only if statements, but also the similar elif and else statements, which can only be used together with if statements. Since these statements all have bodies, and are compatible with functions, we spend a lot of time talking about how they can be combined in different ways. The chapter also introduces a sophisticated nuance of conditionals called Truthiness, which lets us use any type (not just booleans) as if it were a boolean value. Finally, the chapter briefly touches on the related, advanced concept of “Event Handling”, and how it relates to the idea of if statements.
speed_limit = 50
weather = 'sunny'
if weather == 'rainy':
print("It is raining!")
speed_limit = speed_limit - 20
else:
print("Nice day outside!")
print("Speed limit is:", speed_limit)
The first section of the chapter is all about the syntax and usage of if statements. The two essential parts are the conditional (the expression after the if keyword) and the body. The conditional expression is meant to be a question that determines whether the body will be executed, or skipped. The body of an if statement is very similar to the body of a function, except it does not have its own scope; it uses the same scope as the enclosing body. An if statement can also have an else statement afterwards, which has its own body. Should the conditional of an if statement evaluate to False, then the else body will be executed instead. A key insight of the if statement is that it lets us skip over some lines, depending on the values of the variables at that step; we call this behavior “branching” execution, and it makes tracing the program much more complex.
message = "Hello!"
# Test if `message` is not the empty string
if message:
punctuation = message[-1]
else:
punctuation = "No punctuation symbol"
print(punctuation)
The second section of the chapter is about a curious idea called Truthiness. Conceptually, the conditional of an if statement is supposed to be a boolean value, like the result of using the equality operator or a greater-than operator. However, in Python (and many other modern languages), you can use any type of value in a conditional. When you do, Python applies the rules of Truthiness to determine if the value should be treated as True or False. Most values are considered true, with the exception of the empty string, the integer 0, the float 0.0, and the special value None. All other values are considered True, which lets us write convenient shorthand when we want to test if a variable or expression is not one of those values. Note that the value does not actually change to become True or False; this is merely about what Python considers it to be.
from bakery import assert_equal
def count_sides(shape: str) -> int:
if shape == 'triangle':
return 3
elif shape == 'rectangle':
return 4
elif shape == 'circle':
return 1
else:
return 0
assert_equal(count_sides('triangle'), 3)
assert_equal(count_sides('circle'), 1)
assert_equal(count_sides('octogon'), 0)
This section covers how if statements can be combined with functions and even other if statements to make much more complex programs. The indentation rules for the bodies of these statements are consistent, but can still be tricky to follow. The control flow is also a little tricky, since a function can suddenly have more than one return statement, because lines can be skipped based on different conditions. This section also introduces the elif statement, which can appear any number of times after an if statement (but must always come before the else statement, if there is one). The elif statement lets you specify bodies that should be executed when the if statement (and any previous elif statements) are skipped. Only one if/elif/else body will be executed in a chain. The section also covers some ways that if statements are misused, such as in functions that return boolean values, or when programmers unnecessarily test the equality of a boolean value.
To help see the different ways that if statements can be used, the penultimate section covers a list of “Logical Patterns” that provide templates of code to you, the programmer. The idea for each pattern is to fill in the blanks of the template, modifying the structure as needed. There are six patterns covered in this section. They can be somewhat narrow in their use, and are more like guidelines than strict rules, but they should help give more examples of how code can be structured.
from drafter import *
@route
def index(state: int) -> Page:
content = Div(
"Current number: ",
bold(str(state)),
Button("Increase", "increase_state"),
Button("Decrease", "decrease_state"),
)
return Page(state, content)
@route
def increase_state(state: int) -> Page:
return index(state + 1)
@route
def decrease_state(state: int) -> Page:
return index(state - 1)
start_server(7)
The final section is about how the drafter web-app library flips the usual execution model by building around route functions. When a user clicks a link, the corresponding route function is executed. This means that we must provide the functions to the Button component, without directly calling the function inline. These route functions allow us to have more complicated logic, such as if statements, in the routes.