Skip to main content
Commonmark migration
Source Link

###Handle invalid input

Handle invalid input

###Class approach

Class approach

###Handle invalid input

###Class approach

Handle invalid input

Class approach

deleted 7 characters in body
Source Link
Phrancis
  • 20.5k
  • 6
  • 70
  • 155
def get_divisor_text_pairs(self) -> list:
    pair_list = []
    response = 'y'
    while response.lower() == 'y':
        input_is_valid = False
        while (input_is_valid ==not False)input_is_valid:
            divisor = input('Divisor? ')
            try:
                divisor = int(divisor)
                input_is_valid = True
            except ValueError:
                print('"{0}" is not a valid number.'.format(divisor))
        text = input('Text? ')
        pair = DivisorTextPair(divisor, text)
        pair_list.append(pair)
        response = input('Input Another Divisor (y/n)? ')
    return pair_list
def get_divisor_text_pairs(self) -> list:
    pair_list = []
    response = 'y'
    while response.lower() == 'y':
        input_is_valid = False
        while (input_is_valid == False):
            divisor = input('Divisor? ')
            try:
                divisor = int(divisor)
                input_is_valid = True
            except ValueError:
                print('"{0}" is not a valid number.'.format(divisor))
        text = input('Text? ')
        pair = DivisorTextPair(divisor, text)
        pair_list.append(pair)
        response = input('Input Another Divisor (y/n)? ')
    return pair_list
def get_divisor_text_pairs(self) -> list:
    pair_list = []
    response = 'y'
    while response.lower() == 'y':
        input_is_valid = False
        while not input_is_valid:
            divisor = input('Divisor? ')
            try:
                divisor = int(divisor)
                input_is_valid = True
            except ValueError:
                print('"{0}" is not a valid number.'.format(divisor))
        text = input('Text? ')
        pair = DivisorTextPair(divisor, text)
        pair_list.append(pair)
        response = input('Input Another Divisor (y/n)? ')
    return pair_list
Source Link
Phrancis
  • 20.5k
  • 6
  • 70
  • 155

###Handle invalid input

I found an issue with the way you handle some user input:

Start Number?  hello
Traceback (most recent call last):
  File "python", line 7, in <module>
  File "python", line 9, in fizzbuzz
ValueError: invalid literal for int() with base 10: 'hello'

Which is a consequence of this conversion to int without checking that it actually can be converted to int:

int(input('Start number? ')) # and others like it

You could use a while loop along with try...except to continue asking for input until it is usable:

input_is_valid = False
while not input_is_valid:
    start_num = input('Start Number? ')
    end_num =input('End Number? ')
    try:
        start_num = int(start_num)
        end_num = int(end_num)
        input_is_valid = True
    except ValueError:
        print('Invalid number input for start "{0}" or end "{1}".'.format(start_num, end_num))

It may also be worthwhile to consider adding another check to make sure the start number is less than the ending number to prevent confusing behavior if that were not the case.


Another user input related concern is this:

while response == 'y':

Albeit very minor, it treats capital Y as not yes. Simple fix of course:

while response.lower() == 'y':

Your class divisor_text_pair() (by the way, class names in Python should follow TitleCase) has no functionality beyond holding two values. Using a native namedtuple type instead would simplify the code while still allowing you to retrieve the values with dot notation x.divisor and x.text:

from collections import namedtuple

DivisorTextPair = namedtuple('DivisorTextPair', 'divisor text')

class FizzBuzz(): #...

The syntax to use a namedtuple is like that of a class:

pair = DivisorTextPair(divisor, text)

###Class approach

While you class fizzbuzz() approach can be and has been critiqued, I would like to approach it from the angle actually using your class approach, but in a better way.

Your main class is really more of a procedure, as it does not have a constructor, and a lot of the logic is directly in the body of the class, rather than in methods.

P.S.: Note that I will be using Python 3.5 type hints in the method/function signatures, which I recommend to use.


In my refactor of your class (runnable demo on repl.it), the first section would be the constructor and what happens once __init__ is called:

class FizzBuzz():
    def __init__(self):
        self.start_fizzbuzz()

Along with a method to control the general flow:

    def start_fizzbuzz(self) -> None:
        """Controls the overall logic of a FizzBuzz program."""
        start_num, end_num = self.get_start_end_numbers()
        pair_list = self.get_divisor_text_pairs()
        self.print_numbers_and_texts(start_num, end_num, pair_list)

Note the use of Iterable Unpacking (often referred to as "tuple unpacking") in start_num, end_num = self.get_start_end_numbers() (that method will return a tuple, read on). The "long" way of writing the same thing without using tuple unpacking would be like this:

start_end_nums = self.get_start_end_numbers()
start_num = start_end_nums[0]
end_num = start_end_nums[1]

From there, we are getting the start and end numbers from a method where I moved the user input logic to:

def get_start_end_numbers(self) -> tuple:
    input_is_valid = False
    while not input_is_valid:
        start_num = input('Start Number? ')
        end_num =input('End Number? ')
        try:
            start_num = int(start_num)
            end_num = int(end_num)
            input_is_valid = True
        except ValueError:
            print('Invalid number input for start "{0}" or end "{1}".'.format(start_num, end_num))
    return start_num, end_num

The get_divisor_text_pairs() method is what you'd expect it to be, with above applied:

def get_divisor_text_pairs(self) -> list:
    pair_list = []
    response = 'y'
    while response.lower() == 'y':
        input_is_valid = False
        while (input_is_valid == False):
            divisor = input('Divisor? ')
            try:
                divisor = int(divisor)
                input_is_valid = True
            except ValueError:
                print('"{0}" is not a valid number.'.format(divisor))
        text = input('Text? ')
        pair = DivisorTextPair(divisor, text)
        pair_list.append(pair)
        response = input('Input Another Divisor (y/n)? ')
    return pair_list

print_numbers_and_texts() method is essentially unchanged (except for the type hints in the signature)