back

python workout: exercise 14

restaurant

problem

In this exercise, I want you to create a new constant dict, called MENU, representing the possible items you can order at a restaurant. The keys will be strings, and the val- ues will be prices (i.e., integers). You should then write a function, restaurant, that asks the user to enter an order:

  • If the user enters the name of a dish on the menu, the program prints the price and the running total. It then asks the user again for their order.
  • If the user enters the name of a dish not on the menu, the program scolds the user (mildly). It then asks the user again for their order.
  • If the user enters an empty string, the program stops prompting and prints the total amount.

For example, a session with the user might look like this:

Order: sandwich
sandwich costs 10, total is 10
Order: tea
tea costs 7, total is 17
Order: elephant
Sorry, we are fresh out of elephant today.
Order: <enter>
Your total is 17

Note that you can always check to see if a key is in a dict with the in operator. That returns True or False.

attempts

I don’t really like managing user input. But here goes.

We shouldn’t need a try...except block to manage input, seeing as we can test for the empty string directly. So this should be straightforward:

MENU = {
    "blueberry muffin": 3,
    "croissant": 4,
    "breakfast wrap": 6,
    "smoothie": 5,
    "green salad": 4,
    "sandwich": 10,
    "tea": 7
}
def restaurant():
    total = 0
    while True:
        order = input("Order: ")
        if not order:
            break
        if order not in MENU:
            print(f"Sorry, we are fresh out of {order} today.")
            continue
        price = MENU[order]
        total += price
        print(f"{order} costs {price}, total is {total}")

    print(f"Your total is {total}")

 restaurant()
Order: sandwich
sandwich costs 10, total is 10
Order: tea
tea costs 7, total is 17
Order: elephant
Sorry, we are fresh out of elephant today.
Order:
Your total is 17

solution

The book’s implementation:

MENU = {'sandwich': 10, 'tea': 7, 'salad': 9}

def restaurant():
    total = 0
    while True:
        order = input('Order: ').strip()

        if not order:
            break
        if order in MENU:
            price = MENU[order]
            total += price
            print(f'{order} is {price}, total is {total}')
        else:
            print(f'We are fresh out of {order} today')
    print(f'Your total is {total}')

restaurant()
Order: sandwich
sandwich is 10, total is 10
Order: tea
tea is 7, total is 17
Order: elephant
We are fresh out of elephant today
Order:
Your total is 17

I like the use of str.strip() on the input to be a bit more resilient. And maybe even the control flow…

beyond the exercise

user login

  • problem

    Create a dict in which the keys are usernames and the values are passwords, both represented as strings. Create a tiny login system, in which the user must enter a username and password. If there is a match, then indicate that the user has successfully logged in. If not, then refuse them entry.

  • attempts

    This shouldn’t be a particularly difficult extension. It doesn’t drift much away from the original problem’s solution:

    users = {
        "alice": "password123",
        "bob": "letmein",
        "charlie": "securepass",
        "diana": "ilovecoffee",
        "eve": "123456"
    }
    def login():
        username = input("Username: ").strip()
        if username in users:
            password = input(f"Passowrd for {username}: ").strip()
            if users[username] == password:
                print(f"Succesfully logged in as {username}!")
            else:
                print(f"Password for {username} was incorrect.")
        else:
            print(f"No username {username}.")
    
    login()
    
    >>> login()
    Username: bob
    Passowrd for bob: letmein
    Succesfully logged in as bob!
    >>> login()
    Username: bob
    Passowrd for bob: password
    Password for bob was incorrect.
    >>> login()
    Username: john
    No username john.
    

temperatures

  • problem

    Define a dict whose keys are dates (represented by strings) from the most recent week and whose values are temperatures. Ask the user to enter a date, and dis- play the temperature on that date, as well as the previous and subsequent dates, if available.

  • attempts

    If we assume we just have to print the immediately preceding day’s temperature and the immediately succeeding day’s one, this should again be straightforward. The only challenge is that dict keys are not sorted. So there’s not easy way of accessing the needed dates, least of all when dates are represented as strings.

    So, our best bet is probably to convert strings to datetime objects as and when we need to, giving something like:

    from datetime import datetime, timedelta
    
    TEMPS = {
        "2025-08-11": 22.5,
        "2025-08-12": 24.1,
        "2025-08-13": 26.3,
        "2025-08-14": 25.8,
        "2025-08-15": 23.7,
        "2025-08-16": 21.9,
        "2025-08-17": 19.4
    }
    
    def temp():
        date = input("Date: ").strip()
    
        template =  "%Y-%m-%d"
        date_datetime = datetime.strptime(date, template)
        one_day = timedelta(1)
    
        day_before = (date_datetime-one_day).strftime(template)
        day_after = (date_datetime+one_day).strftime(template)
    
        print(f"Temperature on {date}: {TEMPS[date]}C")
        if day_before in TEMPS:
            print(f"Temperature the day before on {day_before}: {TEMPS[day_before]}C")
        if day_after in TEMPS:
            print(f"Temperature the day after on {day_before}: {TEMPS[day_after]}C")
    
    >>> temp()
    Date: 2025-08-14
    Temperature on 2025-08-14: 25.8C
    Temperature the day before on 2025-08-13: 26.3C
    Temperature the day after on 2025-08-13: 23.7C
    >>> temp()
    Date: 2025-08-17
    Temperature on 2025-08-17: 19.4C
    Temperature the day before on 2025-08-16: 21.9C
    >>> temp()
    Date: 2025-08-11
    Temperature on 2025-08-11: 22.5C
    Temperature the day after on 2025-08-10: 24.1C
    

    Is it the most elegant solution? Probalby not. But it works and leveraging datetime and timedelta makes things easy.

age calculator

  • problem

    Define a dict whose keys are names of people in your family, and whose values are their birth dates, as represented by Python date objects (http://mng.bz/ jggr). Ask the user to enter the name of someone in your family, and have the program calculate how many days old that person is.

  • attempts

    First things first. The exercise does make a good point of using datetime.date. We probably should have used it over datetime.datetime in the previous exercise.

    Other than that, this should be straightforward. The only challenge will be turning the timedelta that results from subtracting datetime.date from datetime.date.today().

    After some quick research, dateutil.relativedelta seems to solve all our problems. There’s literally an example solution to our age calculation problem.

    So, drawing form that, we get something like:

    from dateutil.relativedelta import relativedelta
    from datetime import date
    
    FAMILY = {
        "Alice Johnson": date(1985, 3, 14),
        "Bob Johnson": date(1982, 7, 22),
        "Emma Johnson": date(2010, 1, 5),
        "Liam Johnson": date(2015, 9, 30),
        "Sarah Johnson": date(2008, 11, 12)
    }
    
    def age():
        name = input("Family member: ").strip()
        if name in FAMILY:
            today = date.today()
            age = relativedelta(today, FAMILY[name])
            print(f"{name} is {age.years} years old.")
    
    age()
    
    >>> age()
    Family member: Bob Johnson
    Bob Johnson is 43 years old.
    

    🤦

    The exercise only asks for the number days old a person is. Not their age in years.

    So, in the end, we don’t need dateutil.relativedelta:

    from datetime import date
    
    FAMILY = {
        "Alice Johnson": date(1985, 3, 14),
        "Bob Johnson": date(1982, 7, 22),
        "Emma Johnson": date(2010, 1, 5),
        "Liam Johnson": date(2015, 9, 30),
        "Sarah Johnson": date(2008, 11, 12)
    }
    
    def age():
        name = input("Family member: ").strip()
        if name in FAMILY:
            print(f"{name} is {(date.today()-FAMILY[name]).days} days old.")
    
    age()
    
    >>> age()
    Family member: Bob Johnson
    Bob Johnson is 15734 days old.
    
mail@jonahv.com