Modify the program to register multiple phones for the same person. This also allows you to register the type of telephone number: cell phone, landline, home, or work.
Answer:
##############################################################################
# Python From Scratch
# Author: Nilo Ney Coutinho Menezes
# Editora Novatec (c) 2010-2025 - LogiKraft 2025
# Site: https://pythonfromscratch.com
# ISBN: 978-85-7522-949-1 (Paperback), 978-85-7522-950-7 (hardcover), 978-85-7522-951-4 (ebook)
#
# File: chapter 09/exercise-09-28.py.py
##############################################################################
# As the file format becomes increasingly complex,
# we'll use Python's pickle module to save and read the address book.
#
# Extra challenge:
# Modify the program to display a phone management submenu.
# This submenu would be displayed when adding and changing phones.
# Operations: add new phone, delete phone, change phone
import pickle
address_book = []
# Variable to mark a change in the address book
changed = False
phone_types = ["mobile", "landline", "home", "work", "fax"]
def ask_name(default=""):
name = input("Name: ")
if name == "":
name = default
return name
def ask_phone(default=""):
phone = input("Phone: ")
if phone == "":
phone = default
return phone
def ask_phone_type(default=""):
while True:
type = input("Phone type [%s]: " % ",".join(phone_types)).lower()
if type == "":
type = default
for t in phone_types:
if t.startswith(type):
return t # Returns the full name
else:
print("Invalid phone type!")
def ask_email(default=""):
email = input("Email: ")
if email == "":
email = default
return email
def ask_birthday(default=""):
birthday = input("Birthday: ")
if birthday == "":
birthday = default
return birthday
def show_data(name, phones, email, birthday):
print(f"Name: {name.capitalize()}")
print("Phone(s):")
for phone in phones:
print(f"\tNumber: {phone[0]:15s} Type: {phone[1].capitalize()}")
print(f"Email: {email}\nBirthday: {birthday}\n")
def ask_filename():
return input("File name: ")
def search(name):
mname = name.lower()
for p, e in enumerate(address_book):
if e[0].lower() == mname:
return p
return None
def new():
global address_book, changed
name = ask_name()
if search(name) is not None:
print("Name already exists!")
return
phones = []
while True:
number = ask_phone()
type = ask_phone_type()
phones.append([number, type])
if confirm("that you want to register another phone") == "N":
break
email = ask_email()
birthday = ask_birthday()
address_book.append([name, phones, email, birthday])
changed = True
def confirm(operation):
while True:
option = input(f"Confirm {operation} (Y/N)? ").upper()
if option in "YN":
return option
else:
print("Invalid response. Choose Y or N.")
def delete():
global address_book, changed
name = ask_name()
p = search(name)
if p is not None:
if confirm("deletion") == "Y":
del address_book[p]
changed = True
else:
print("Name not found.")
def change():
global changed
p = search(ask_name())
if p is not None:
name, phones, email, birthday = address_book[p]
print("Found:")
show_data(name, phones, email, birthday)
name = ask_name(name) # If nothing is entered, keeps the value
for phone in phones:
number, type = phone
phone[0] = ask_phone(number)
phone[1] = ask_phone_type(type)
email = ask_email(email)
birthday = ask_birthday(birthday)
if confirm("change") == "Y":
address_book[p] = [name, phones, email, birthday]
changed = True
else:
print("Name not found.")
def list():
print("\nAddress Book\n\n------")
# We use the enumerate function to get the position in the address book
for position, e in enumerate(address_book):
# Print the position
print(f"\nPosition: {position}")
show_data(e[0], e[1], e[2], e[3])
print("------\n")
def read_last_saved_address_book():
last = last_address_book()
if last is not None:
read_file(last)
def last_address_book():
try:
file = open("last address book pickle.dat", "r", encoding="utf-8")
last = file.readline()[:-1]
file.close()
except FileNotFoundError:
return None
return last
def update_last(name):
file = open("last address book pickle.dat", "w", encoding="utf-8")
file.write(f"{name}\n")
file.close()
def read_file(filename):
global address_book, changed
file = open(filename, "rb")
address_book = pickle.load(file)
file.close()
changed = False
def read():
global changed
if changed:
print(
"You haven't saved the list since the last change. Do you want to save it now?"
)
if confirm("saving") == "Y":
save()
print("Read\n---")
filename = ask_filename()
read_file(filename)
update_last(filename)
def sort():
global changed
# You can sort the list as shown in the book
# with the bubble sort method
# Or combine Python's sort method with lambdas to
# define the list key
# address_book.sort(key=lambda e: return e[0])
end = len(address_book)
while end > 1:
i = 0
swapped = False
while i < (end - 1):
if address_book[i] > address_book[i + 1]:
# Option: address_book[i], address_book[i+1] = address_book[i+1], address_book[i]
temp = address_book[i + 1]
address_book[i + 1] = address_book[i]
address_book[i] = temp
swapped = True
i += 1
if not swapped:
break
changed = True
def save():
global changed
if not changed:
print("You haven't changed the list. Do you want to save it anyway?")
if confirm("saving") == "N":
return
print("Save\n------")
filename = ask_filename()
file = open(filename, "wb")
pickle.dump(address_book, file)
file.close()
update_last(filename)
changed = False
def validate_integer_range(question, start, end):
while True:
try:
value = int(input(question))
if start <= value <= end:
return value
except ValueError:
print(f"Invalid value, please enter between {start} and {end}")
def menu():
print(
"""
1 - New
2 - Change
3 - Delete
4 - List
5 - Save
6 - Read
7 - Sort by name
0 - Exit
"""
)
print(f"\nNames in address book: {len(address_book)} Changed: {changed}\n")
return validate_integer_range("Choose an option: ", 0, 7)
read_last_saved_address_book()
while True:
option = menu()
if option == 0:
break
elif option == 1:
new()
elif option == 2:
change()
elif option == 3:
delete()
elif option == 4:
list()
elif option == 5:
save()
elif option == 6:
read()
elif option == 7:
sort()