A validation library

In the last lesson, the Scoobies wrote the input part of a "Goats in Space-ace-ace..." program. There were three input variables: small_goats, medium_goats, and large_goats. The validation loops for each one were almost the same. Here's the small goat code, with the lines that change for medium and large goats marked.

  1. # How many small goats?
  2. is_input_ok = False
  3. while not is_input_ok:
  4.     # Start off assuming data is OK.
  5.     is_input_ok = True
  6.     # Get input from the user.
  7.     user_input = input('Small goats? ')
  8.     # Is the input numeric?
  9.     try:
  10.         small_goats = int(user_input)
  11.     except ValueError:
  12.         print('Sorry, you must enter a whole number.')
  13.         is_input_ok = False
  14.     # Check the range.
  15.     if is_input_ok:
  16.         if small_goats < 0 or small_goats > 100:
  17.             print('Sorry, please enter a number zero or more, but no more than 100.')
  18.             is_input_ok = False

(I didn't include the testing code.)

There are about 670 characters here. Only 35 characters are specific to small goats. That's only 5%. When we copy the code for medium and large goats, 95% of the code remains the same.

Reflect

Why is all this repeated code a problem?

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
Adela
Adela

I can think of a few things, but I'm guessing the most important is that updating the code would cost more.

Right! If we need to change something, we need to change it three times, then test each one. Easy to make a mistake.

Goat validation function

OK, let's use this stuff on our goat problem. Here's the code again. The highlighted stuff is what we want to be different for medium and large goats.

  1. # How many small goats?
  2. is_input_ok = False
  3. while not is_input_ok:
  4.     # Start off assuming data is OK.
  5.     is_input_ok = True
  6.     # Get input from the user.
  7.     user_input = input('Small goats? ')
  8.     # Is the input numeric?
  9.     try:
  10.         small_goats = int(user_input)
  11.     except ValueError:
  12.         print('Sorry, you must enter a whole number.')
  13.         is_input_ok = False
  14.     # Check the range.
  15.     if is_input_ok:
  16.         if small_goats < 0 or small_goats > 100:
  17.             print('Sorry, please enter a number zero or more, but no more than 100.')
  18.             is_input_ok = False

You could make a function out of that, reusing it for every goat type.

  1. def input_num_of_goats(prompt):
  2.     is_input_ok = False
  3.     while not is_input_ok:
  4.         # Start off assuming data is OK.
  5.         is_input_ok = True
  6.         # Get input from the user.
  7.         user_input = input(prompt)
  8.         # Is the input numeric?
  9.         try:
  10.             goats = int(user_input)
  11.         except ValueError:
  12.             print('Sorry, you must enter a whole number.')
  13.             is_input_ok = False
  14.         # Check the range.
  15.         if is_input_ok:
  16.             if goats < 0 or goats > 100:
  17.                 print('Sorry, please enter a number zero or more, but no more than 100.')
  18.                 is_input_ok = False
  19.     return goats
  20.  
  21. small_goats = input_num_of_goats('Small goats?')
  22. medium_goats = input_num_of_goats('Medium goats?')
  23. large_goats = input_num_of_goats('Large goats?')