Search code examples
pythonloopsdictionarymethodstuples

Why is the value in this dictionary's list of tuples not printing?


I am trying to print the value of a key when a float string is entered.

Here's my code:

number_dict = {1: 'One', 2: 'Two', 3: 'Three', 4: 'Four', 5: 'Five', 6: 'Six', 7: 'Seven', 8: 'Eight', 9: 'Nine', 0: 'Zero', '-': 'Negative', '.': 'Point'}

number = input('Enter a number: ')
print(f'As Text:', end = ' ')
for char in number:
    for key, value in number_dict.items():
        if char == key:
            print(value, end = ' ')
        elif int(char) == key:
            print(value, end = ' ')

What am I doing wrong? Why aren't the values associated with the '.' and '-' keys printing? They should be accessed in the elif condition.

There is already a try and except block to account for the ValueError. I just didn't want to post the code in its entirety, but I am aware of the error and already accounted for.

Thank you for your help in advance!!


Solution

  • This loop will never run more than once because it ends with a break:

    for key, value in number_dict.items():
        if char == key:
            print(number_dict[key], end = ' ')
        elif int(char) == key:
            print(number_dict[key], end = ' ')
        break
    

    The break doesn’t make any sense. Once you remove that, you get to the main problem, which is that if int(char) throws an exception (like it does when you pass it the "-" or "." characters), you’re catching the exception outside the loop. This also means that the loop doesn’t run for the remaining items of the dictionary.

    To understand what’s happening better, using a debugger, step through the loop with char = "-".

    Now, you can fix this by catching the exception inside the loop:

    for key, value in number_dict.items():
        if char == key:
            print(number_dict[key], end = ' ')
        else:
            try:
                if int(char) == key:
                    print(number_dict[key], end = ' ')
            except ValueError:
                pass  # do nothing
    

    But none of this is how you should use a dictionary. Dictionaries are for looking things up directly by key; by iterating over it to check every key, you’re defeating the point. To clean up your code, I would recommend starting by making your dict keys homogeneous, i.e. all strings instead of a mix of strings and integers:

    number_dict = {'1': 'One', '2': 'Two', '3': 'Three', '4': 'Four', '5': 'Five', '6': 'Six', '7': 'Seven', '8': 'Eight', '9': 'Nine', '0': 'Zero', '-': 'Negative', '.': 'Point'}
    

    Now you can get the value corresponding to any character, regardless of whether it’s a digit, with number_dict[char].

    It’s also good practice to avoid throwing and catching exceptions when possible, and when you do have to, to make the try cover as little as possible – otherwise, you risk catching things you didn’t expect and mishandling them.

    while True:
        number = input('Enter a number: ')
    
        # can check this ahead of time! helps limit the `try` responsibilities
        if ',' in number:
            print('Please try again without entering commas.')
            continue
    
        # much smaller `try`!
        try:
            float(number)
        except ValueError:
            print(f'"{number}" is not a valid number. Please try again.')
            continue
    
        print(f'As Text:', end = ' ')
        for char in number:
            print(number_dict[char], end = ' ')
    

    Finally, note that float accepts some things you didn’t account for, like constants "-inf"/"inf"/"nan", scientific notation "1e-1", and whitespace. You should use stricter validation, which also means not needing a try at all (good!). Here’s an example of doing it with regular expressions:

    import re
    
    number_dict = {'1': 'One', '2': 'Two', '3': 'Three', '4': 'Four', '5': 'Five', '6': 'Six', '7': 'Seven', '8': 'Eight', '9': 'Nine', '0': 'Zero', '-': 'Negative', '.': 'Point'}
    
    while True:
        number = input("Enter a number: ")
    
        if "," in number:
            print("Please try again without entering commas.")
            continue
    
        if not re.fullmatch(r"-?(?!\.?\Z)[0-9]*(?:\.[0-9]*)?", number):
            print(f"{number!r} is not a valid number. Please try again.")
            continue
    
        text = " ".join(number_dict[char] for char in number)
        print(f"As Text: {text}")
    

    but since you probably don’t know regular expressions yet, try writing a strict validation function as an exercise, with a loop and the str.isdigit method you’ve already used. Consider questions like whether "1." should print “One Point” or “One” or an error!