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 ifs and whiles, 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 ifs. 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_okmakes 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.