Branching in Python (Part 1)
Translating from pseudocode
Pseudocode if a > b return a else return b Indent
Python if a > b: return a else: return b Indent evenly
To go from pseudocode to Python is just a matter of adding colons at the end of lines. In both, if
can appear with or without else
.
Python convention
Indent four spaces.
Example: chocolate sales
Let's start with an example that determines the cost of buying chocolate plus an optional donation.
Assume that the cost of chocolate bars is $2 each plus an optional $10 donation. The steps involved in the calculation of the cost is as follows:
- Ask the user for the number of bars.
- Compute cost of the chocolate.
- Ask the user if a donation is desired.
- If a donation is made, add $10 to the cost. Otherwise, do nothing.
We'll make use of user input twice: first to determine the number of bars sold and then to determine whether or not to include the donation. This suggests two possible courses of action, depending on whether or not the buyer is giving a donation. In the first case, we add 10 to the cost and otherwise we do nothing.
Creating the function
We add the steps mentioned before as comments as we write the function.
BAR_COST = 2 # cost of a bar of chocolate
To determine the total cost of the bars, we will make use of the cost of a single bar. This suggests using a constant.
def is_yes(word):
return word[0] == "y" or word[0] == "Y"
We make use of user input to determine whether or not to include the donation. The condition should be True
if the user writes yes
and False
otherwise. To distinguish between the two cases, we will use of the function is_yes
, which we developed earlier. This will interpret answers of “yup”, “yeah” and “you bet” as True
. Also, some answers meaning no, such as “You must be kidding”. So think twice about being sarcastic with a computer.
## Ask user for number of bars
bars = int(input("Enter number of bars: "))
We need to remember to convert the user's input to a integer for the number of bars.
## Compute cost of chocolate
cost = bars * BAR_COST
We to compute the cost of the chocolate.
## Ask user if donation desired
donate = input("Donate $10? ")
We use user input again to determine whether a donation is requested.
if is_yes(donate):
cost = cost + 10
Our condition is simply the value of is_yes
on the user input, and when the condition is True
, we add $10 to the cost.
print(cost)
Finally, we print the total cost.
Here is the complete function when all parts are put together:
BAR_COST = 2 # cost of a bar of chocolate
def is_yes(word):
return word[0] == "y" or word[0] == "Y"
## Ask user for number of bars
bars = int(input("Enter number of bars: "))
## Compute cost of chocolate
cost = bars * BAR_COST
## Ask user if donation desired
donate = input("Donate $10? ")
if is_yes(donate):
cost = cost + 10
print(cost)
Let's see the function in action. When the function is run, we get the following text and input box:
Enter number of bars:
We enter the value 4 in the input box and hit enter. This gives the output
Enter number of bars: Donate $10?
We enter "y" in the second input box and hit enter, resulting in the output
Enter number of bars: Donate $10? 18
Example: odd-length string
As another example, let's revisit the problem of determining if the input is an odd-length string.
def is_odd_string(word):
We start by writing the header, using word
as the name of our input.
if len(word) % 2 == 1:
return True
We can check if the length is odd by seeing that the remainder is 1 when it is divided by 2, and then returning True
.
print(is_odd_string("a"))
print(is_odd_string("ab"))
We add some print
statements to test our function.
Here's our function when all parts are put together:
def is_odd_string(word):
if len(word) % 2 == 1:
return True
print(is_odd_string("a"))
print(is_odd_string("ab"))
What happens when we run our function? We get the following output:
True None
Why did we get None
on the second input? Remember, it means that we didn't return a value in this case. How can we fix it? We can add two lines so that we return False
if the condition is False
:
def is_odd_string(word):
if len(word) % 2 == 1:
return True
else:
return False
print(is_odd_string("a"))
print(is_odd_string("ab"))
Now the function works properly on both inputs:
True False
Example: simplified Pig Latin
As another example, consider a simplified version of Pig Latin. This function takes a word as input and outputs a new word depending on whether the first character of the input word is a vowel or a consonant. The new word is formed as follows:
- If the first character is a vowel, the new word is formed by putting together, in order, the input word, "w", and "ay".
- If the first character is a consonant, the new word is formed by putting together, in order, the suffix of the input word without the first character, the first character, and "ay".
Creating the function
def easy_pig(word):
We will assume that the input is nonempty and consists only of letters, so that we can use the function is_vowel
which we created earlier.
When the condition is True
, that is, the word starts with a vowel, we create the first part of the translation into Pig Latin by starting with the word and then adding a "w"
to the end. We'll later add "ay"
to each case, since each ends with "ay"
.
if is_vowel(word[0]):
part = word + "w"
When the condition is False
, the word starts with a consonant. The translation into Pig Latin is formed by chopping off the first character and then concatenating it to the end.
return part + "ay"
Finally, we append "ay" and return the result.
Here's our function when all parts are put together:
def easy_pig(word):
if is_vowel(word[0]):
part = word + "w"
else:
part = word[1:] + word[0]
return part + "ay"
We can make the code shorter by appending "ay" at the same time as forming the rest of the string. Here each case ends with a return:
def easy_pig(word):
if is_vowel(word[0]):
return word + "w" + "ay"
else:
return word[1:] + word[0] + "ay"
Note that the branches never rejoin.
Making the code even shorter
Consider the figures (1)-(3) shown below. As in our earlier pictures, the red circles represent instructions. This time we have a red triangle, which represents a statement, and blue dashed circles, which represent instructions that might not be executed depending on the way branching occur. In each of the figures, there are three red circles, followed by a red triangle, two blue dashed circles, and two red circles.
If the branches do not rejoin, we can write the function without using else
. Here's how. In the first branch, the condition is true. So, the upper red circles and then the blue dashed circles are executed, with the function returning a value at the last blue dashed circle. Notice that in this case, the lower red circles are not used. This scenario is shown in figure (2).
In the second branch, the condition is false. In this case, the order of steps goes through the upper red circles, the statement, and the lower red circles without going through the blue dashed circles, as shown in figure (3).
So, in one branch we use the upper red circles and then the blue dashed circles, and in the other branch we use the upper red circles and then the lower red circles. The parts that are the same for both cases appear in the upper red circles. The parts that are different appear in the blue dashed circles for the first branch and in the lower red circles for the second branch.
To write our function in this way, first case returns within the if
, and the second case appears as the steps after the if
:
def easy_pig(word):
if is_vowel(word[0]):
return word + "w" + "ay"
return word[1:] + word[0] + "ay"
The return
within the if
is like the dashed blue circles and the return
after the if
is like the lower red circles. This raises the question of whether this shorter version is better than the previous code.
Clarity first
Clearer is better.
The answer is what you expected: clearer is better. In this case, it isn't obvious that shorter is clearer, so it isn't obvious that shorter is better.
Example: off peak rates
As a final example, let's revisit off peak rates. Suppose we want to figure out whether a particular time is eligible for offpeak rates, that is, it is not between 9 am and 5 pm. We'll use 24-hour time, so offpeak means not between 9 and 17. Accordingly, we'll assume our input is an integer in the range from 0 to 23. We choose the name offpeak
for our function and the name hour
for our parameter. This time, we return a string "Off peak" or "Peak" depending on the input. Now we can fill in the two cases.
def offpeak(hour):
As usual, we start with the header.
if hour < 9 or hour > 17:
We write a condition that is True
when the rates are off peak, that is, in 24-hour time, the hour is before 9 or after 17.
return("Off peak")
We return
"Off peak" if the condition is True
.
else:
Since there are two possible courses of action, we add else
.
return("Peak")
We return
"Peak" if the condition is False
.
print(offpeak(7))
print(offpeak(9))
print(offpeak(20))
Now we add some test cases.
Here's our function when all parts are put together:
def offpeak(hour):
if hour < 9 or hour > 17:
return("Off peak")
else:
return("Peak")
print(offpeak(7))
print(offpeak(9))
print(offpeak(20))
We get the following output when the code is run:
Off peak Peak Off peak