Calories Tracker Project — Round 2
We left Round 1 with a question. One input or five. We have an answer now.
Five. For a simple reason: five separate inputs mean five separate opportunities to validate the data. One line means one shot — and if anything is wrong, everything breaks. We'll come back to that tradeoff when we add file handling. For now, we build on what we have.
The first thing that should catch your attention is the key. We used name in Round 1 — it made sense to get the function working. But in practice, we'll log Chicken Breast more than once. Probably many times. And food_dict["Chicken Breast"] = [...] doesn't add a new entry. It overwrites the existing one.
What would make each entry unique? The date — or better, the date and the exact time. And here's where the datetime module solves two problems at once: it automates one of our five inputs, and it gives us a key that's guaranteed to be unique.
import datetime
timestamp = datetime.datetime.now().strftime("%Y-%m-%d,%H:%M:%S")
We don't keep this as a datetime object — we convert it to a string immediately with strftime(). The comma in the format is intentional: it will let us split date from time later when we need just the date for reports. More on that when we get there.
We're now down to four inputs. That's a 20% reduction in manual data entry — which, statistically, doesn't sound dramatic. Over months of daily logging, it adds up.
Now we protect the function. Not everything needs the same level of validation. name and measure are display fields — they don't drive any calculations, so we just make sure they're not empty. An empty string evaluates to False in Python. while not name keeps asking until the user types something.
name = ""
while not name:
name = input("Food name: ")
We initialize name as an empty string first. Without that, while not name would throw a NameError — the variable doesn't exist yet, so Python can't evaluate it.
quantity and calories are different. They drive the math. We need numbers — and positive ones. quantity can be a float: 1.5l, 0.5kg. calories are always whole numbers.
For both, the pattern is the same: while True keeps the loop running, try/except catches anything that can't be converted to a number, and the if check rejects zero and negatives. break only fires when everything passes.
while True:
try:
quantity = float(input("Quantity: "))
if quantity > 0:
break
print("Quantity must be greater than 0.")
except ValueError:
print("Invalid quantity. Enter a number.")
while True:
try:
calories = int(input("Calories: "))
if calories > 0:
break
print("Calories must be greater than 0.")
except ValueError:
print("Invalid calories. Enter a whole number.")
The full function now looks like this:
import datetime
food_dict = {}
def add_food_item():
name = ""
while not name:
name = input("Food name: ")
while True:
try:
quantity = float(input("Quantity: "))
if quantity > 0:
break
print("Quantity must be greater than 0.")
except ValueError:
print("Invalid quantity. Enter a number.")
measure = ""
while not measure:
measure = input("Measure: ")
while True:
try:
calories = int(input("Calories: "))
if calories > 0:
break
print("Calories must be greater than 0.")
except ValueError:
print("Invalid calories. Enter a whole number.")
timestamp = datetime.datetime.now().strftime("%Y-%m-%d,%H:%M:%S")
food_dict[timestamp] = [name, quantity, measure, calories]
add_food_item()
print(food_dict)
We call it. We enter the data:
Food name: Chicken Breast
Quantity: 200
Measure: g
Calories: 175
We check the result:
{'2025-04-02,14:32:11': ['Chicken Breast', 200.0, 'g', 175]}
The timestamp is the key. The data is clean. The types are correct — quantity is a float, calories is an int.
We can add entries. We can add the same food twice. Each entry gets its own key. Nothing overwrites anything.
The function works. Next, we make it loop — and we start thinking about what to do with the data once it's in.