How to create a dictionary with a fixed number of valid user entries in Python?

Viewed 92

I want to write a Python program that creates a dictionary with a fixed number of entries entered by the user. For each entry, if the user enters invalid input, I want the program to prompt the user to retry until he enters a valid input. Unfortunately this program does not work:

phoneBook = {}
numberOfEntries = int(input("Enter number of entries to phone book: "))

for i in range(numberOfEntries):
    try:
        name, phoneNumber = input(
            "Enter details - name, two spaces, phone number: ").split("  ")
        phoneBook[name] = phoneNumber
    except:
        print("Incorrect, two spaces between name and phone number.")
        i -= 1

print(phoneBook)
2 Answers

i is reassigned at each iteration of the for loop, which overwrites all previous assignments, including those made in the body like your assignment i -= 1. So use a while loop instead.

Also a few suggestions:

  • You should validate all your inputs, including the number of entries to the phone book.
  • You should only catch the most specific exceptions (ValueError here), so you rarely need to catch all exceptions (BaseException)—when you do not know specifically which exceptions to catch, catch Exception, not BaseException. Your expression-less except clause except: catches all exceptions, so it is equivalent to the except clause except BaseException:. BaseException catches (besides Exception) SystemExit, KeyboardInterrupt, and GeneratorExit, which you usually do not want to catch (cf. the Python exception hierarchy).
  • You should follow the Python naming convention lower_case_with_underscores for function and variable names, not mixedCase (cf. PEP 8).

The new program:

while True:
    try:
        user_input = input("Enter number of entries to phone book: ")
        i = int(user_input)
    except ValueError:
        print("Invalid input, enter a number.")
    else:
        break

phone_book = {}

while i:
    try:
        user_input = input("Enter contact (name, 2 spaces, phone number): ")
        name, phone_number = user_input.split("  ")
    except ValueError:
        print("Invalid input, enter 2 spaces between name and phone number.")
    else:
        phone_book[name] = phone_number
        i -= 1

print(phone_book)

An algorithmic pattern appears therefore you can create a function that encapsulates it so that you do not repeat yourself (cf. the DRY principle):

def prompt(condition, message, warning, validate, process, new):
    output = None
    while condition:
        try:
            user_input = input(message)
            valid_input = validate(user_input)
        except ValueError:
            print(warning)
        else:
            output = process(valid_input)
            condition = new(condition)
    return output


condition = True
message = "Enter number of entries to phone book: "
warning = "Invalid input, enter a number."
validate = lambda x: int(x)
process = lambda x: x
new = lambda x: False
entry_count = prompt(condition, message, warning, validate, process, new)

condition = entry_count
message = "Enter contact (name, 2 spaces, phone number): "
warning = "Invalid input, enter 2 spaces between name and phone number."
validate = lambda x: x.split("  ") if x.index("  ") else None
phone_book = {}
process = lambda x: phone_book.update({x[0]: x[1]})
new = lambda x: x - 1
prompt(condition, message, warning, validate, process, new)

print(phone_book)

You could amend your for loop to, instead of using a try catch block, use a while conditional to validate against your input, i.e. while the user input is not valid, prompt the user for a new input. That would make your for loop be:

    for i in range(numberOfEntries):
        details = input("Enter details - name, two spaces, then number: ").split("  ")
        while len(details) != 2:
            print("Incorrect, two spaces between name and number...")
            details = input("Enter details - name, two spaces, then number: ").split("  ")
        name, phoneNumber = details
        phoneBook[name] = phoneNumber
Related