We've got a long validation test, and it's in the code twice:
- while service_level != 'g' and service_level != 'o' \
- and service_level != 's' and service_level != 'q':
- ...
- if service_level != 'g' and service_level != 'o' \
- and service_level != 's' and service_level != 'q':
It works, but from a programming cost point of view, having the test just once would be better.
Why? Hint: it's not about writing the code the first time.

Adela
Oh, OK, thanks for the hint.
I think it's about making changes. If we wanted to add a new option, like h
for help or something, we'd have two tests to change.

Ray
What's wrong with that? Copy-and-paste is easy.

Adela
Yes, but the more times the test is in the code, the more likely we'll mess up the program when adding a new option. That means more time debugging.
Adela's right. Most programmers spend more time updating existing programs, rather than writing new programs. Makes sense. If you've got a program that almost does the job, it's a lot cheaper to change the existing program, than make a new one.
It's not a big deal with just one repeated test, but real programs can have dozens of them. The more complicated the tests in if
s and while
s, the easier it is to mess things up.
Not graded. So why do it?
Here's another way to do things.
Let's add a new variable. Its job is to know whether the input is valid or not:
- is_input_ok = (service_level == 'g' or service_level == 'o' \
- or service_level == 's' or service_level == 'q')
Then, instead of repeating the test, we use is_input_ok
.

Ethan
I'm confused.
OK. Type this in the console:
- 5 + 2.5
Python evaluates (works out) the expression, and gives you back 7.5.
Another:
- 2 < 5
Python evaluates the expression, and gives you back...
What does Python give you?

Georgina
It gave True
, because 2 is less than 5.
Right.
Right. So just as 5 + 2.5
is an expression returning a value, so 2 < 5
is an expression returning a value.
Not graded. So why do it?
We can check out the data type of a value with the type()
function. In the console:
- type(5 + 2.5)
What do you get?

Georgina
It said float
. The expression 5 + 2.5
return a float.
OK. Now try:
- type(2 < 5)
What did you get?

Ray
It says bool
.
Aye. Boolean is a new data type. We know about these types so far:
- String: characters you can type, like "The cannibal passed his brother in the woods."
- Float: a number that might have a decimal part, like 8.32.
- Boolean: either true or false.
Let's put in some variables. Assignment (=
) takes a value on the right, and puts it into the variable on the left:
- variable = value
Another example, using the same two expressions.
- x = 5 + 2.5
- y = 2 < 5
- print('x is', x)
- print('y is', y)
Paste those four lines into the console. What's the output?

Ethan
I got:
- x is 7.5
- y is True
Indeed. And when I check out ye olde Variable Explorer:
The type column shows the types.
One more:
- cows = 4
- pigs = float(input('How many pigs? '))
- is_more_pigs = (pigs > cows)
- print('More pigs than cows? ', is_more_pigs)
(Don't run the code yet.) What's the output going to be, if the user types 3
for the number of pigs?

Ethan
If they type 3 for pigs, then line 3 says is_more_pigs
is false, since 3 is not more than 4. So I should get More pigs than cows? False
Indeed! Try it to check.
Booleans have many uses. One is to break apart if
s. These are equivalent:
- if sheep > goats and cattle_dogs > (sheep/20) and shepherds > (sheep/50):
- or
- is_got_enough = sheep > goats and cattle_dogs > (sheep/20) and shepherds > (sheep/50)
- if is_got_enough:
Notice started the variable name with is_
. That's a common standard, using is_
, was_
, or something else that looks like it's a yes/no thing.
This is what the code is right now:
- service_level = ''
- while service_level != 'g' and service_level != 'o' \
- and service_level != 's' and service_level != 'q':
- service_level = input(
- 'Service level (g=great, o=ok, s=sucked, q=quit)? '
- )
- # Normalize service level
- service_level = service_level.strip().lower()
- # Validate service level
- if service_level != 'g' and service_level != 'o' \
- and service_level != 's' and service_level != 'q':
- print('Please enter G, O, S, or Q.')
Here's another version, using a boolean.
- is_input_ok = False
- while not is_input_ok:
- service_level = input('Service level (g=great, o=ok, s=sucked, q=quit)? ')
- # Normalize service level
- service_level = service_level.strip().lower()
- # Validate service level
- is_input_ok = service_level == 'g' or service_level == 'o' \
- or service_level == 's' or service_level == 'q'
- if not is_input_ok:
- print('Please enter G, O, or S.')
Georgina, could you run through the code?

Georgina
Sure. The first line initializes the boolean. It's set to false, so line 2 will run the code in the loop.
Lines 3 and 5 get and normalize user input.
Line 7 sets the boolean to true or false, depending on whether the user entered valid input.
Hmm. Could I use parens around the expression? To better see what's going on.
Sure, and that means you don't need to use the \ line continuation thing, either.
- is_input_ok = (service_level == 'g' or service_level == 'o'
- or service_level == 's' or service_level == 'q')
Actually, if you wanted, you could lay it out like this:
- is_input_ok = (
- service_level == 'g'
- or service_level == 'o'
- or service_level == 's'
- or service_level == 'q'
- )
That's how I would do it in a real program. Makes it easier to understand what's going on.
Let's change the code to:
- is_input_ok = False
- while not is_input_ok:
- service_level = input('Service level (g=great, o=ok, s=sucked, q=quit)? ')
- # Normalize service level
- service_level = service_level.strip().lower()
- # Validate service level
- is_input_ok = (
- service_level == 'g'
- or service_level == 'o'
- or service_level == 's'
- or service_level == 'q'
- )
- if not is_input_ok:
- print('Please enter G, O, or S.')

Georgina
Cool! I like it.
After lines 7 to 12 run, is_input_ok
is either true or false. If the input is hot OK, show an error. Then go back to the top of the loopn
Oh! I just noticed. You flipped the logical expression (a logical expression is either true or false) around. Before, we had:
- if service_level != 'g' and service_level != 'o' \
- and service_level != 's' and service_level != 'q':
- print('Please enter G, O, S, or Q.')
That tests whether the input is invalid. If not g and not o and not s and not q, that's invalid.
In the new code, you test whether the input is valid.
is_input_ok = ( service_level == 'g' or service_level == 'o' or service_level == 's' or service_level == 'q' )
If service_level
is g, o, s, or q, then is_input_ok
is true. The input's OK.
I like that better.

Adela
Yes, I do too. Easier to understand.
Booleans make life easier.
- The name of
is_input_ok
makes it clear what the variable means. - We only have one copy of the logical expression, making changes easier.
- The code is easier to understand. That means easier to change and debug.
Win win!
Summary
Exercises
Add loop for meal cost.