Pythonic Code Day 3 of 3
Day 36 of 100
This 3 day challenge got me to thinking about the Python projects I have been working on and the room for improvement that I have. The challenge was to look at your projects and code and implement some principles of pythonic code in order to improve its readability and simplicity. When I looked back at my projects and what I had written, I certainly see room for improvement but but it would be improving code and applications that I would almost immediately abandon.
Instead I decided to start a small project that was inspired by the Real Python Ideas for Intermediate Projects article I recently read. I have started to use some of what I have learned to build a command land contacts database. This project isn't so much something that fills a great need but it is a project to apply and extend what I have learned to a real project. To start, I was to apply what I have learned about classes, error handling, logging, testing, and pythonic code to the project.
So far, I was able to cobble together a small application that prompts a user to choose what they would like to do, then choose weather they want to create a new contact, search for a contact, print out a list of contacts, or quit the application. It is still in the very beginning stages, but there is something here that works, at least initially, which is enough to keep me going.
contacts.py
from classes import Contact
def main():
print_header()
program_loop()
contact_list = []
def print_header():
print('-' * 45 + '\n')
print(' ' * 17 + 'CONTACTS DB' + '\n')
print('-' * 45 + '\n')
def create_contact():
contact = Contact.create_new_contact()
contact_list.append(contact)
def search_contacts(contact_list):
search_parameter = input(f'Would you like to search by [F]irst or [L]ast name: ')
search_params = ['f', 'l']
try:
if search_parameter.lower() in search_params:
# search by first letter of first name
if search_parameter.lower() == 'f':
search_letter = input(f'What is the first letter of the first name you are searching for: ')
results = []
for contact in contact_list:
if search_letter.lower() == contact.first_name[0].lower():
results.append(contact)
if results:
for result in results:
print(result.full_name())
else:
print(f'No results.')
# TODO implement last name search
# TODO implement full name search
# TODO implement search by all parameters
else:
raise ValueError
except:
print('Input not recognized.')
# Ask for search parameter - first name, last name, etc
# Ask for exact match or first letter match
# Ask for search term to match
# Search contact list for search term
# Return results to user and let the user pick which one to look at full contact info
def print_contacts(contact_list):
contact_num = 1
for contact in contact_list:
print(f'Contact {contact_num}: {contact.first_name} {contact.last_name}')
contact_num += 1
def program_loop():
valid_inputs = ['c', 'p', 'q', 's']
while True:
task = input(f'What would you like to do?\n'
f'\t[C]reate new contact\n'
f'\t[P]rint contacts\n'
f'\t[S]earch contacts\n'
f'\t[Q]uit\n'
f'\t> ')
try:
if task.lower() in valid_inputs:
if task.lower() == 'c':
create_contact()
elif task.lower() == 'p':
print_contacts(contact_list)
elif task.lower() == 's':
search_contacts(contact_list)
elif task.lower() == 'q':
print('Good Bye')
break
else:
raise ValueError
except:
print('Please enter "C", "R", or "Q" to continue')
continue
if __name__ == '__main__':
main()
# TODO Database support
# TODO File i/o
# TODO Tests
# TODO Logging
# TODO Email/share contact
# TODO Look at pyinputplus for input validation
# TODO so many more things
I put the classes in a separate file.
classes.py
class Contact:
"""
A contact object
Attributes:
first_name(string)
last_name(string)
address1(string)
address2(string)
city(string)
state(string)
zip(int)
phone(string)
email(string)
"""
def __init__(self, first_name, last_name,): # address1, address2, city, state, zip, phone1, email
self.first_name = first_name
self.last_name = last_name
# self.address1 = address1
# self.address2 = address2
# self.city = city
# self.state = state
# self.zip = zip
# self.phone1 = phone1
# self.email = email
def full_name(self):
return f'{self.first_name} {self.last_name}'
@classmethod
def create_new_contact(self):
while True:
try:
first_name = input('First name: ')
if not first_name:
raise ValueError
last_name = input('Last name: ')
if not last_name:
raise ValueError
return self(first_name, last_name)
except:
print('Invalid input. Try again.')
# continue