ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ
Project: Contact book
Time to build something you use every day: a contact book. You type commands, and it adds, finds, deletes, and lists contacts, all kept in a dictionary. Here's the finished program in use:
Command: add
Name: Dawit
Number: 0900 000 004
Saved Dawit.
Command: find
Name: Yonas
No contact called Yonas.
Command: list
1. Abel: 0900 000 001
2. Dawit: 0900 000 004
3. Hana: 0900 000 002
4. Selam: 0900 000 003
Command: quit
Goodbye!It combines a dict (lesson 4.4), enumerate and sorted (4.6), a while loop
(Module 3), and match (lesson 2.5). You'll build it in five milestones, running it
after each one. The Input box for each milestone already holds commands that try every
part. The numbers are made up.
Milestone 1: list the contacts
Start with three contacts already in a dict, and print them numbered, in alphabetical
order. sorted() on a dict sorts its keys, the names; each name then looks up its
number. Call the loop's counter position: in milestone 3, number will mean a phone
number, and one name shouldn't mean two things.
መልመጃ
A numbered list
Print every contact, numbered from 1, sorted by name.
1. Abel: 0900 000 001
2. Hana: 0900 000 002
3. Selam: 0900 000 003Your code
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
# Print each contact, numbered and sorted by nameIn the editor, press Escape then Tab to move on.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")Milestone 2: the menu loop
Now ask for commands until the user types quit. A match inside while True picks
what to do; case _ catches anything else. One detail to be sure of first:
ጥያቄ
A break inside a case runs. What does it leave?
መልመጃ
Commands in a loop
Ask Command: over and over. list prints the contacts as in milestone 1, quit
prints Goodbye! and stops, and anything else prints
Unknown command. Try add, find, delete, list, or quit.
Your code
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")In the editor, press Escape then Tab to move on.
One answer per line, given to input() in order.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
while True:
command = input("Command: ")
match command:
case "list":
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")
case "quit":
print("Goodbye!")
break
case _:
print("Unknown command. Try add, find, delete, list, or quit.")Milestone 3: add and find
add asks for a name and a number and saves them. What if the name is already there?
Predict:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
contacts = {"Hana": "0900 000 002"}
contacts["Hana"] = "0900 000 222"
print(len(contacts), contacts["Hana"])Python prints
1 0900 000 222
A key appears once in a dict, so saving Hana again replaces her number instead of adding a second Hana. That's fine, but the user should be told: print Updated instead of Saved.
find asks for a name and prints the number. A missing name must get a friendly
message, never a KeyError: check with in first (lesson 4.4).
መልመጃ
Add and find
Add two cases. add asks Name: and Number: , saves the contact, and prints
Saved Dawit. for a new name or Updated Hana. for one already there. find asks
Name: and prints Hana: 0900 000 222, or No contact called Yonas.
Your code
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
while True:
command = input("Command: ")
match command:
case "list":
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")
case "quit":
print("Goodbye!")
break
case _:
print("Unknown command. Try add, find, delete, list, or quit.")In the editor, press Escape then Tab to move on.
One answer per line, given to input() in order.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
while True:
command = input("Command: ")
match command:
case "add":
name = input("Name: ")
number = input("Number: ")
if name in contacts:
print(f"Updated {name}.")
else:
print(f"Saved {name}.")
contacts[name] = number
case "find":
name = input("Name: ")
if name in contacts:
print(f"{name}: {contacts[name]}")
else:
print(f"No contact called {name}.")
case "list":
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")
case "quit":
print("Goodbye!")
break
case _:
print("Unknown command. Try add, find, delete, list, or quit.")Notice the order in add: the check comes before saving. After saving, the name is
always in the dict, so every contact would say "Updated".
Milestone 4: delete, safely
del contacts[name] removes a contact, but on a name that isn't there it stops the
whole program:
Also make list say so when the book is empty: an empty dict is falsy (lesson 2.4), so
if not contacts: is true exactly when there are none.
መልመጃ
Delete with checks
Add delete: ask Name: , then print Deleted Selam. or No contact called Yonas.
Make list print No contacts yet. when the dict is empty.
Your code
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
while True:
command = input("Command: ")
match command:
case "add":
name = input("Name: ")
number = input("Number: ")
if name in contacts:
print(f"Updated {name}.")
else:
print(f"Saved {name}.")
contacts[name] = number
case "find":
name = input("Name: ")
if name in contacts:
print(f"{name}: {contacts[name]}")
else:
print(f"No contact called {name}.")
case "list":
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")
case "quit":
print("Goodbye!")
break
case _:
print("Unknown command. Try add, find, delete, list, or quit.")In the editor, press Escape then Tab to move on.
One answer per line, given to input() in order.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
contacts = {"Selam": "0900 000 003", "Abel": "0900 000 001", "Hana": "0900 000 002"}
while True:
command = input("Command: ")
match command:
case "add":
name = input("Name: ")
number = input("Number: ")
if name in contacts:
print(f"Updated {name}.")
else:
print(f"Saved {name}.")
contacts[name] = number
case "find":
name = input("Name: ")
if name in contacts:
print(f"{name}: {contacts[name]}")
else:
print(f"No contact called {name}.")
case "delete":
name = input("Name: ")
if name in contacts:
del contacts[name]
print(f"Deleted {name}.")
else:
print(f"No contact called {name}.")
case "list":
if not contacts:
print("No contacts yet.")
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")
case "quit":
print("Goodbye!")
break
case _:
print("Unknown command. Try add, find, delete, list, or quit.")That's the complete contact book. Test it the way a user would break it: delete someone twice, find a name with a typo, type a command in capitals.
Milestone 5: several numbers, partial search (stretch)
People have more than one number. Make each value a list of numbers: a dict of
lists. add on an existing name appends to that person's list instead of replacing it.
Create the empty list first if the name is new.
And find can accept part of a name: in works on text too, so "el" in "Abel" is
True. Use a comprehension (lesson 4.7) to collect the matching names. The match is
case-sensitive for now; Module 6 shows how to ignore case.
መልመጃ
A dict of lists (stretch)
Store numbers as lists. add appends and prints Abel has 2 numbers. (or 1 number).
find asks Name or part of it: and prints every number of every matching contact,
or No contact matches Zed. list prints each name numbered, with its numbers
indented on the lines below.
Your code
contacts = {"Selam": ["0900 000 003"], "Abel": ["0900 000 001"], "Hana": ["0900 000 002"]}
while True:
command = input("Command: ")
match command:
case "add":
name = input("Name: ")
number = input("Number: ")
if name in contacts:
print(f"Updated {name}.")
else:
print(f"Saved {name}.")
contacts[name] = number
case "find":
name = input("Name: ")
if name in contacts:
print(f"{name}: {contacts[name]}")
else:
print(f"No contact called {name}.")
case "delete":
name = input("Name: ")
if name in contacts:
del contacts[name]
print(f"Deleted {name}.")
else:
print(f"No contact called {name}.")
case "list":
if not contacts:
print("No contacts yet.")
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}: {contacts[name]}")
case "quit":
print("Goodbye!")
break
case _:
print("Unknown command. Try add, find, delete, list, or quit.")In the editor, press Escape then Tab to move on.
One answer per line, given to input() in order.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
contacts = {"Selam": ["0900 000 003"], "Abel": ["0900 000 001"], "Hana": ["0900 000 002"]}
while True:
command = input("Command: ")
match command:
case "add":
name = input("Name: ")
number = input("Number: ")
if name not in contacts:
contacts[name] = []
contacts[name].append(number)
count = len(contacts[name])
if count == 1:
print(f"{name} has 1 number.")
else:
print(f"{name} has {count} numbers.")
case "find":
part = input("Name or part of it: ")
matches = [name for name in sorted(contacts) if part in name]
if not matches:
print(f"No contact matches {part}.")
for name in matches:
for number in contacts[name]:
print(f"{name}: {number}")
case "delete":
name = input("Name: ")
if name in contacts:
del contacts[name]
print(f"Deleted {name}.")
else:
print(f"No contact called {name}.")
case "list":
if not contacts:
print("No contacts yet.")
for position, name in enumerate(sorted(contacts), start=1):
print(f"{position}. {name}")
for number in contacts[name]:
print(f" {number}")
case "quit":
print("Goodbye!")
break
case _:
print("Unknown command. Try add, find, delete, list, or quit.")ዋና ዋና ነጥቦች
- A dict is the right shape for "find the number by name"; a dict of lists holds several numbers per name.
- Check with
inbefore reading or deleting a key, so a typo never ends the program with aKeyError. matchinsidewhile Truemakes a menu;breakin a case leaves the loop, not just thematch.enumerate(sorted(contacts), start=1)gives a numbered, alphabetical list.- Build in milestones and run after each one: list, menu, add and find, delete, then extras.