Storing and using information in Python (Part 2)
Example: painting rooms
Let's revisit our room painting example to show how to translate it from pseudocode to Python. We need to find the area of walls of 20 rooms, each of 6 × 8 with 10-foot ceilings. The calculation in the painting example is given below.
The area of all rooms = 20 × The area of one room
The area of one room = 2 × ( The area of big wall + The area of small wall )
The area of the big wall = 8 × 10
The area of the small wall = 6 × 10
We can use the short but descriptive names all, one, big, and small.
Pseudocode | Python |
---|---|
big ← 8 * 10 | big = 8 * 10 |
small ← 6 * 10 | small = 6 * 10 |
one ← 2 * (big + small) | one = 2 * (big + small) |
all ← 20 * one | all = 20 * one |
This example is quite straightforward: we've replaced the arrows with equals signs in changing from pseudocode to Python. The one other change we have made is in the name of the variable all
. There are two reasons for this: all_rooms
is more descriptive and, although all
is not a reserved keyword, it is the name of a built-in function. Avoiding it is preferable, even if not required.
Example: a simple code
How might we use variables when exchanging the first and middle characters of a nonempty string? Recall that we create our coded string by concatenating the four pieces in this order:
- middle character,
- substring from second to one before the middle,
- first character, and
- substring from one after the middle to the last.
Using variables
We can start by using variables for values we use repeatedly, such as the string itself and the position of the middle character:
word = "mystery" # string to encode
mid = math.floor(len(word) / 2) # middle position
Notice that we use the variable word
in the definition of the variable mid
, but only after word
as been defined. Then, expressing the middle character is succinct and easy to understand: word[mid]
.
To indicate the first substring using the slice operation, we indicate that we want to throw away everything before position 1 and everything including and after the middle position: word[1:mid]
.
The variable "mid" makes this easy to read and understand. Even for the first character, a shorter way of indicating the string helps with clarity: word[0]
.
For the second substring, again the expression is much shorter due to the variable for the middle position. We extract the substring from one after the middle to the last using word[mid + 1:]
.
The entire expression is both shorter and more understandable:
print(word[mid] + word[1:mid] + word[0] + \
word[mid + 1:])
Using more variables
We could have chosen to use even more variables in addition to “word” and “mid”: one for the middle character, middle = word[mid]
; one for the substring from second to one before the middle, first_piece = word[1:mid]
; one for the first character, first = word[0]
; and one for the substring from one after the middle to the last, second_piece = word[mid + 1:]
.
This results in an even shorter final expression:
print(middle + first_piece + first + second_piece)
Comparing the solutions
Here is the first solution and we didn't use any variables (no variables):
print("mystery"[math.floor(len("mystery") / 2)] + \
"mystery"[1:math.floor(len("mystery") / 2)] + \
"mystery"[0] + \
"mystery"[math.floor(len("mystery") / 2) + 1:])
Here is the second solution when we use two variables (some variables):
word = "mystery" # string to encode
mid = math.floor(len(word) / 2) # middle position
print(word[mid] + word[1 : mid] + word[0] + \
word[mid + 1:])
Even if in total the second solution is not shorter than the first solution, it is more understandable.
Good habit
Use variables for frequently-used expressions.
For this reason, it is a good habit to use variables for frequntly-used expressions. So, does using even more variables result in an even better solution? Not necessarily. Consider the code with more variables:
word = "mystery" # string to encode
mid = math.floor(len(word) / 2) # middle position
middle = word[mid]
first_piece = word[1:mid]
first = word[0]
second_piece = word[mid + 1:]
print(middle + first_piece + first + second_piece)
Is this more clear than the previous solution? The print statement is shorter, but to understand what is being printed means going back to remembering what the first and second piece are. More variables is not always better. There is often a tradeoff and not always an obvious best answer.
Good habit
Aim for clarity.
Your goal is communication, so make clarity your top priority.
Example: parking cost
Let's consider one last example. Suppose we wish to park a car for 31 days at a cost of $100 for each week and $20 a day for any extra days. What intermediate calculations do we need?
- Determine the number of weeks in 31 days.
- Determine the number of days remaining.
- Calculate cost of the weeks.
- Calculate costs of days remaining.
- Total the two costs.
We'll need the number of weeks of parking and the number of days that are not part of those weeks. We can use those to figure out the costs of the full weeks as well as the leftover days, with the answer being the total of those two numbers.
Determining costs
We can start by making the costs into constants as well as the number of parking days and the days in the week:
WEEK_CHARGE = 100 # cost per week
DAY_CHARGE = 20 # cost per day
DAYS = 31 # total days
DAYS_IN_WEEK = 7 # days per week
Except the number of days in a week, any of these could be made into a variable, using the argument that we might change them. We'll talk about this issue more in the future. For now, let's leave them as constants. Then, to figure out the number of full weeks in 31 days and leftover days, we use quotient and remainder, and assign the results to variables:
weeks = DAYS // DAYS_IN_WEEK
days = DAYS % DAYS_IN_WEEK
Then, to calculate the costs for weeks and days remaining, we multiply these by the charges for each, again assigning the results to variables:
week_cost = weeks * WEEK_CHARGE
day_cost = days * DAY_CHARGE
Finally, to determine the total we simply add the two costs:
print(week_cost + day_cost)
Forming the solution
Good habit
Keep notes as comments and use blank lines for clarity.
Since our aim is clarity, let's keep our notes as comments and insert some blank lines between groups of lines:
WEEK_CHARGE = 100 # cost per week
DAY_CHARGE = 20 # cost per day
DAYS = 31 # total days
DAYS_IN_WEEK = 7 # days per week
## Determine number of weeks, days remaining
weeks = DAYS // DAYS_IN_WEEK
days = DAYS % DAYS_IN_WEEK
## Calculate cost of weeks, cost of days remaining
week_cost = weeks * WEEK_CHARGE
day_cost = days * DAY_CHARGE
## Total two costs
print(week_cost + day_cost)
Could we have made this shorter by introducing fewer variables? Yes. Would it have been clearer? Maybe yes, maybe no. You will continually be having to make judgment calls to determine what will be best for the reader.