Safe Paws Project — Round 1/5
In how many ways can you describe an animal? Many. But if you're describing one to someone who might adopt it — how many of those ways actually matter?
A lost animal poster doesn't tell you where it sleeps, or what its favorite food is, or how many vacations it's been on. It tells you what you need to recognize it. Same principle here. We're not building a biography. We're building a profile.
So — what's relevant when someone is looking for an animal to adopt? Size. Age. Health. Species. A name. And a status — available or not. That gives us this:
animal = ["Lassie", "dog", "medium", 4, "healthy", "available"]
And all of these together form a dictionary. We move faster now — the baggage from the Calories Tracker is already packed. We're not starting from zero.
The question is: which of these fields could serve as a unique key? None of them. Lassie is a name we could give to ten dogs. Medium-sized healthy dogs will be many. Available is the whole point of Safe Paws.
We need something that identifies each animal unambiguously. Simple, readable, memorable. A number — incremental, starting at 1. Animal 1, animal 2, animal 3. The kind of number you can write on a file, read over the phone, reference in an adoption record without any confusion.
To generate it, we read the highest existing ID from the dictionary and add 1. If the dictionary is empty — first run, no animals yet — we start at 1.
def get_next_id():
if not paws_dict:
return 1
all_ids = []
for k in paws_dict.keys():
all_ids.append(int(k))
return max(all_ids) + 1
If the dictionary is empty, we return 1 — first animal, first ID. Otherwise, we build a list of all existing IDs, converting each key to an integer as we go. Keys are stored as integers, but the conversion is a good habit — when we load from file later, everything comes back as a string. max() finds the highest ID in the list. We add 1 and return. Every new animal gets the next number in line.
With that settled, here's the full add function. We standardize size and health — only specific values accepted.
paws_dict = {}
def get_next_id():
if not paws_dict:
return 1
all_ids = []
for k in paws_dict.keys():
all_ids.append(int(k))
return max(all_ids) + 1
def add_paw():
name = ""
while not name:
name = input("Paw name: ")
specie = ""
while not specie:
specie = input("Paw specie: ")
size = ""
while not size or size.lower() not in ["small", "medium", "big"]:
size = input("Paw size (small/medium/big only): ")
size = size.lower()
health = ""
while not health or health.lower() not in ["healthy", "ill"]:
health = input("Paw health status (healthy/ill only): ")
health = health.lower()
while True:
try:
age = int(input("Paw age: "))
if age > 0:
break
print("Paw age must be greater than 0.")
except ValueError:
print("Invalid paw age. Enter a number.")
id = get_next_id()
paws_dict[id] = [name, specie, size, health, age, "available"]
Most fields are strings — simple validation. Size and health accept only specific values — the loop rejects anything else. Age uses the same try/except pattern from the Tracker. Status is always "available" at creation — we don't register an animal that can't be adopted.
We add the menu and we're already further than two full rounds of the Calories Tracker. With less effort. That's the baggage paying off.
while True:
print("\nSafe Paws Menu")
option = input("Choose your option (1-Add paw, q-Quit): ")
if option == "1":
add_paw()
print("Paw added successfully!")
elif option == "q":
break
else:
print("Invalid option!")
We call it. We add two animals:
add_paw() # Lassie, dog, medium, healthy, 4
add_paw() # Whiskers, cat, small, healthy, 2
print(paws_dict)
Output:
{
1: ['Lassie', 'dog', 'medium', 'healthy', 4, 'available'],
2: ['Whiskers', 'cat', 'small', 'healthy', 2, 'available']
}
Animal 1. Animal 2. Clear, readable, useful.
Next — persistence. Same logic as the Tracker, same two functions. The shelter needs to remember its animals.