Is this code simplified? Should I use more functions? - python

So I'm working on this program that opens an external file and then runs through it to see if it contains specific information. Is there a way to simplify it or is the way it is now the most efficient way write this?
def printGender(alist):
if "Female" in alist:
print(alist)
print("Female Students")
def maleInfo(blist):
if "2010" in blist:
print(blist)
print("Students who enrolled in 2010")
def csc2010(clist):
if "CSC" in clist and "2010" in clist and "Female" in clist:
print(clist)
print("Female students who registered in CSC in 2010")
def main():
ref = open("file1.txt","r")
studentList = ref.readlines()
ask = 10
while ask != 0:
print("1) print all female info")
print("2) display all male info from 2010")
print("3) display female students who registered for CSC in 2010")
ask = int(input("Enter option 1, 2, 3 or 0 to quit: "))
if ask == 1:
for i in range(len(studentList)):
alist = studentList[i]
printGender(alist)
elif ask == 2:
for i in range(len(studentList)):
blist = studentList[i]
maleInfo(blist)
elif ask == 3:
for i in range(len(studentList)):
clist = studentList[i]
csc2010(clist)
elif ask == 0:
print("You chose to quit")
break
else:
print("Not a Valid input")
continue
ref.close()
main()
Is there a way to simplify this code so that I don't create three seperate list in the main function.
if ask == 1:
for i in range(len(studentList)):
alist = studentList[i]
printGender(alist)
elif ask == 2:
for i in range(len(studentList)):
blist = studentList[i]
maleInfo(blist)
elif ask == 3:
for i in range(len(studentList)):
clist = studentList[i]
csc2010(clist)
elif ask == 0:
print("You chose to quit")
break
else:
ect...
I was curious to see if there was a shorter way to get the same result. Maybe using a function that runns that section of code but I'm not sure how to do that.

Some problems to be aware of:
the construct
for i in range(len(studentList)):
alist = studentList[i]
printGender(alist)
is pretty nasty; if you actually need i you should use
for i, student in enumerate(student_list):
print_gender(student)
otherwise
for student in student_list:
print_gender(student)
Your functions are poorly named; they don't do what they say they do! printGender prints female students, printMale prints students from 2010, etc. Similarly, your variable names are poorly chosen; alist is not a list of students, it is a single student.
You seem to have a text string per student, at a guess something like 2009, 176915, Jones, Susan, Female, CSC; but you make no attempt to separate out fields. This will lead to annoying problems with students like 2009, 292010, Male, Jill, Female, RCSCA who will be reported as a student in both 2009 and 2010 (false match on student number), and both female and male (false match on last name), and in CSC (false match on course name). You really need to use a better data format - whether .csv or .json or a database, anything which returns named fields - to solve this problem.
Your search options are non-orthogonal and limited to pre-coded options; you have no way of searching, for example, for all CSC students in 2007 without rewriting your program.
Fixing these problems leads you to something like
import json
def record_print_format(record):
return "{Year:4} {Id:6} {Gender:6} {Firstname:>20} {Lastname:<20} {Course:6}".format(**record)
def show_records(records, format_fn=record_print_format):
for r in records:
print(format_fn(r))
num = len(records)
print("{} records:".format(num))
def filter_records(records, field, value):
return [r for r in records if r[field] == value]
def match_year(records, year):
return filter_records(records, "Year", year)
def match_gender(records, gender):
return filter_records(records, "Gender", gender)
def match_course(records, course):
return filter_records(records, "Course", course)
def main():
with open("student_list.json") as studentfile:
all_students = json.load(studentfile)
records = all_students
while True:
print("1: Filter by year")
print("2: Filter by gender")
print("3: Filter by course")
print("8: Show results")
print("9: Clear filters")
print("0: Exit")
option = input("Please pick an option: ").strip()
if option == "1":
year = input("Which year? ").strip()
records = match_year(records, year)
elif option == "2":
gender = input("Which gender? [Male|Female] ").strip()
records = match_gender(records, gender)
elif option == "3":
course = input("Which course? ").strip()
records = match_course(records, course)
elif option == "8":
show_records(records)
elif option == "9":
records = all_students
elif option == "0":
print("Goodbye!")
break
else:
print("I don't recognize that option.")
if __name__=="__main__":
main()

Related

How to understand an undefined error in a function I'm trying to write

I'm a new engineer and I'm writing a simple phone book app in Python. It's pretty self explanatory, as it's a beginner project. When I was writing the function I forgot to tell it what to do if a entry that was being search wasn't found.
I have looked at several examples, and to the best of my growing knowledge base, coded what I thought was correct. I am getting an error and would like to understand it.
Also, optimization is key, so one of my objectives is to learn to code for optimization the first time.
Traceback (most recent call last):
File "/Users/corcoding/Desktop/projects/phonebook-project/phonebook.py", line 20, in <module>
print("phone number of" ,name1, "is", d1==[name])
NameError: name 'name' is not defined
Code:
def menu():
print("-------Lil Black Book--------")
print("[1] Look up an entry")
print("[2] Set an entry")
print("[3] delete an entry")
print("[4] List all entries")
print("[5] Quit")
print("what would you like to do (1-5)?")
menu()
d1 = {}
while True:
n=int(input("enter number [1-5]:-"))
if n ==2:
name=input("enter name:-")
phono=(input("enter phone number:-"))
d1[name]=phono
elif n==1:
name1=input("enter name to SEARCH for phone number in the phone book")
print("phone number of" ,name1, "is", d1[name])
if name1 != d1[name]:
print("entry not found")
if n== 3:
name1=input("enter name to delete:-")
d1.pop(name)
elif n==5:
break
I believe this code may accomplish what you are looking for:
d1 = {}
while True:
n = int(input("enter number [1-5]:-"))
if n == 1:
name1 = input("enter name to SEARCH for phone number in the phone book")
if not(name1 in d1.keys()):
name1 = input("please enter someone who is already in your book")
else:
print("phone number of" ,name1, "is", d1[name1])
elif n == 2:
name = input("enter name:-")
phono = (input("enter phone number:-"))
d1[name]=phono
elif n == 3:
name1 = input("enter name to delete:-")
d1.pop(name)
elif n == 4:
print(d1)
elif n == 5:
break
First off, I ordered the if statements by n so it is easier to read.
Note that indenting does matter in Python! Whatever you want to run inside of an if statement must be indented inside of it.
The main issue is when n = 1. This is because we do not know if name1 exists inside of d1. Therefore, we must first check if name1 exists inside of d1 before calling d1[name1].
Moved up the validation and changed the code.
def menu():
print("-------Lil Black Book--------")
print("[1] Look up an entry")
print("[2] Set an entry")
print("[3] delete an entry")
print("[4] List all entries")
print("[5] Quit")
print("what would you like to do (1-5)?")
menu()
d1 = {}
while True:
n = int(input("enter number [1-5]:-"))
if n == 2:
name = input("enter name:-")
phono = (input("enter phone number:-"))
d1[name] = phono
elif n == 1:
name1 = input(
"enter name to SEARCH for phone number in the phone book")
if name1 != d1.get(name1,None): # Validate name exist
print("entry not found")
else:
print("phone number of", name1, "is", d1[name])
if n == 3:
name1 = input("enter name to delete:-")
d1.pop(name)
elif n == 5:
break
Test run.
[1] Look up an entry
[2] Set an entry
[3] delete an entry
[4] List all entries
[5] Quit
what would you like to do (1-5)?
enter number [1-5]:-1
enter name to SEARCH for phone number in the phone bookDoe
entry not found
enter number [1-5]:-

How can I exit a while loop after the user inputs "0"? If user inputs anything else, I want it to continue

Write a Python program that will ask the user for the name of a movie. Add the movie entered to a list. Continue asking for a movie until the user enters ‘0’.
After all movies have been input, output the list of movies one movie per line.
This is what I've tried:
def main():
movies = []
while movies != 0:
movie = str(input("Enter the name of a movie: "))
if movie == 0:
break
if movie != 0:
movies.append(movie)
print("That's your list")
print(movies)
main()
movie = str(input("Enter the name of a movie: "))
if movie == 0:
break
if movie != 0:
movies.append(movie)
The idea is correct here. But there is one mistake. You are asking for a string input then checking if the string input is an integer.
Try to take a string input but compare it to another string.
if movie == "0":
break
Suggested Code
I changed your code your code up a bit too, much cleaner
def main():
movies = []
while "0" not in movies:
movies.append(str(input("Enter the name of a movie: ")))
print("That's your list")
print(movies[:-1])
main()
Use the break keyword to interrupt either a while or a for loop.
The code given by BuddyBob is not 100% correct because it will include the "0" in the list of movies (since it is first appended).
The code given by ALI NAQI is actually comparing with a lowercase 'o'.
I believe this would be the best way:
def main():
movies = []
while True:
movie = input("Enter the name of a movie: ")
if movie == "0":
break
else:
movies.append(movie)
print("That's your list")
print(movies)
main()
movie = str(input("Enter the name of a movie: "))
if movie == 0:
break
if movie != 0:
movies.append(movie)
This seems good but remember you are comparing string value (movie) with an integer like:
if movie == 0: #thats the mistake . now correct one is listed below
if movie == "o":
break
Hope you understood this.

Using Variables From Other Functions

Hopefully my code and question(s) are clear for understanding. If they are not please provide feed back.
I am fairly new to programing/coding so I decided to develop a program using Python that acts like a pizza ordering system. I eventually would like to use this code to develop a website using Django or Flask.
I have just finished the first step of this program where I am asking the user if this will be for delivery of pickup. Depending on what the user chooses the program will ask for specific information.
The area I feel like I am struggling with the most is developing classes and functions. specifically taking a variables from one function and using that variable in another function. I posted a past example of my code and I was advised that Global variables are not good to use in code. So I am trying really hard to refrain from using them.
Here is the code for reference:
import re
running = True
class PizzaOrderingSys():
"""order a customized pizza for take out or delivery """
def delivery_or_pickup(self): # Is the order for devilery or pickup?
print("\nWill this order be for pickup or delivery?")
self.delivery = input("P - pick up / D - delivery : ")
self.delivery = self.delivery.title()
if self.delivery == "D":
while running == True:
customerName = input("\nName for the order: ")
if not re.match("^[a-zA-Z ]*$", customerName):
print("Please use letters only")
elif len(customerName) == 0:
print("Please enter a vaild input")
else:
customerName = customerName.title()
break
while running == True:
customerPhoneNumber = input("\nEnter a phone number we can contact you at: ")
if not re.match("^[0-9 ]*$", customerPhoneNumber):
print("Please use numbers only")
elif len(customerPhoneNumber) == 0:
print("Please enter a a contact phone number")
else:
break
while running == True:
house_num = input("\nWhat is your house or unit number: ")
if not re.match("^[0-9 /]*$", house_num):
print("Please use numbers only")
elif len(house_num) == 0:
print("Please enter a valid input ")
else:
break
while running == True:
streetName = input("\nStreet name: ")
if not re.match("^[a-zA-Z ]*$", streetName):
print('Please use letters only.')
elif len(streetName) == 0:
print("Please enter a valid input")
else:
streetName = streetName.title()
break
while running == True:
city = input("\nCity: ")
if not re.match("^[a-zA-Z ]*$", city):
print("Please use letters only")
elif len(city) == 0:
print("Please enter a valid input")
else:
city = city.title()
break
while running == True:
zip_code = input("\nZip Code:")
if not re.match("^[0-9 /]*$", zip_code):
print("Please use numbers only")
elif len(zip_code) == 0 or len(zip_code) > 5:
print("Please enter a valid input")
else:
break
elif self.delivery == "P":
while running == True:
customerName = input("\nName for the order: ")
if not re.match("^[a-zA-Z ]*$", customerName):
print("Please use letters only")
elif len(customerName) == 0:
print("Please enter a valid input")
else:
customerName = customerName.title()
break
while running == True:
customerPhoneNumber = input("\nEnter a phone number we can contact you at: ")
if not re.match("^[0-9 ]*$", customerPhoneNumber):
print("Please use numbers only")
elif len(customerPhoneNumber) == 0:
print("Please enter a valid input")
else:
break
else:
print("Please enter P or D ")
delivery_or_pickup()
order = PizzaOrderingSys()
order.delivery_or_pickup()
My question is this: How would I use variables found in one function of my class and use it in another future function??
For example if I wanted to retrieve variables the functions customerName, customerPhoneNumber, house_num, streetName, city, Zip_code found in delivery_or_pick() function and use them in a function called:
def customer_receipt():
What would I need to do to my exiting code or to the def customer_receipt() function to obtain that information?
Any help with my questions or advise on any other area that stick out to you would be be greatly appropriated.
This is my second post on Stackoverflow so I apologize if what i am asking is unclear or the format of my question might is off, I am still learning.
Thank you again.
The idea here is that you can use your class variables to save data between method calls. Methods are functions that belong to a class. For example you could use Python's class initialization and create a dict of orders. Here is a simple example of such system, take a note of the usage of self keyword. self refers to the instance of the class and you can use it to access the variables or methods of the instance:
class PizzaOrderingSys:
def __init__(self):
# Initializing some class variables
self.running = True # Now you can use self.running instead of global running variable
self.orders = {}
def delivery_or_pickup(self):
# Somewhere at the end where you have collected the needed info
order = {
"zip_code": zip_code,
"city": city,
# You can enter all of the needed data similarly
}
order_id = "SomeIdHere" # ID could be anything, it just should be unique
self.orders[order_id] = order
return order_id
def customer_receipt(self, id):
# Now you can access all of the order here with self.orders
order = self.orders.get(id) # Select some specific order with id.
# Using get to avoid the situation
# where no orders or invalid id would raise an exception
if order:
receipt = f"Order {id}:\nCustomer city {order['city']}"
else:
receipt = None
return receipt
pizzasystem = PizzaOrderingSys()
order_id = pizzasystem.delivery_or_pickup()
receipt = pizzasystem.customer_receipt(order_id)
print(receipt)
# >>> Order 1235613:
# Customer city Atlantis
I recommend that you read more about classes, for example, python docs have great material about them.

How can I get my function to go back to a certain point in code after elif statement?

I'm trying to get user input for adding persons details to a dictionary, after they go through the first while loop. It asks them if they would like to add another entry, if the user enters anything other than "y" or "n" I want it to say ivalid entry, and ask them again, if they then enter "y" or "n" I would like it to go back to the start of the while loop again.
Tried changing the code, the loops and the if, elif and else statements but can't figure it out.
import pprint
everyone = {}
def people_database():
yesno = "y"
while yesno == "y":
name = input("What is the name you would like to add?: ")
age = input("What is the age you would like to add?: ")
residence = input("What is the residence you would like to add?: ")
everyone["people"] = {"Name": name,
"Age": age,
"Residence": residence}
yesno = input("Would you like to add another? Enter y or n: ")
if yesno == "y" or yesno == "Y":
continue
elif yesno == "n" or yesno == "N":
break
else:
while yesno != "y" or yesno != "Y" or yesno != "n" or yesno != "N":
print("Not a valid input.")
yesno = input("Would you like to add another? Enter y or n: ")
if yesno == "y" or yesno == "Y":
continue
elif yesno == "n" or yesno == "N":
break
people_database()
If after entering wrong entry they then input correct entry the function should start again.
I think it would be very beneficial to construct a function for recieving the yes / no input. But in my opinion it need not be recursive in contrast to liamhawkins' answer. A simple while loop would suffice. And no need to print any error statement, as it is pretty obvious to the user that something went wrong if the question is posed again with clear instructions how to answer.
def get_decision(question: str='y/n: '):
ans = ''
while ans not in ['y', 'n']:
ans = input(question)
return ans
everyone = {}
def people_database():
while True:
name = input("What is the name you would like to add?: ")
age = input("What is the age you would like to add?: ")
residence = input("What is the residence you would like to add?: ")
everyone["people"] = {"Name": name,
"Age": age,
"Residence": residence}
if get_decision('Would you like to add another? Enter y or n: ') == 'n':
break
people_database()
You can of course extend the list of accepted answers and make the decision condition more complex accordingly, but this is a minimal example. In my opinion accepting only one symbol for a particular action is clearer than guessing what the user ment, although in this case it is pretty unambiguous.
Side note, I don't know the full story behind your case, but it seems that overriding the people key in the dictionary is not useful in the loop. You'd probably want an incrementing ID to mimic a "database":
people = {}
def people_database():
person_id = 0
while True:
name = input('Name?: ')
age = input('Age?: ')
residence = input('Residence?: ')
people[person_id] = {
'Name': name,
'Age': age,
'Residence': residence
}
if get_decision('Would you like to add another? Enter y or n: ') == 'n':
break
person_id += 1
if __name__ == '__main__':
people_database()
Your second while loop is testing whether yesno is not y or not Y or not n or not N. It will always run, because it can't be all of these cases at the same time. Change your ors to ands
Also, your first while loop should also check for uppercase Y.

Exiting a For Loop & Enumeration (Python)

I'm new to Python and working on a bootcamp project... and I'm absolutely making it harder than it needs to be...
What I'm looking to ultimately do, is create the following:
Name: Titanic \n
Director: Spielberg \n
Year: 1997 \n\n
Name: The Matrix \n
Director: Waskowskis \n
Year: 1996 \n\n
AFTER I've added them with the "(A)dd Movie function... So, firstly, I can't seem to 'exit' the For Loop... once I run it, it just repeats indefinitely... and beyond that, I'm not able to get the formatting correct if I try to use "enumerate".
Here's my code: (the portion I'm talking about is under the "def show_movies" function:
import sys
import random
import os
movies = []
def menu():
global user_input
print("Welcome to 'The Movie Program!!'")
print("(A)dd movie to your list")
print("(L)ist movies you've added")
print("(S)earch for movies in your list")
user_input = str(input("Which function would you like to do?:\n\n""Selection: ").capitalize())
while user_input != 'Q':
if user_input == 'A':
add_movies()
elif user_input == 'L':
show_movies()
elif user_input == 'A':
search_movies()
else:
print("\n\n--Unknown command--Please try again.\n")
print("Welcome to 'The Movie Program!!'")
print("(A)dd movie to your list")
print("(L)ist movies you've added")
print("(S)earch for movies in your list")
user_input = str(input("Which FUNCTION would you like to do?:\n\n""Selection: ").capitalize())
def add_movies():
#name = (input('What is the title of the movie?: ').title())
#director = str(input("Who was the director of this movie?: ").title())
year = None
while True:
try:
name = (input('What is the title of the movie?: ').title())
director = str(input("Who was the director of this movie?: ").title())
year = int(input("What was the release year?: "))
except ValueError:
print("Only numbers, please.")
continue
movies.append({
"name": name,
"director": director,
"year": year
})
break
menu()
add_movies()
def show_movies():
for movie in movies:
print(f"Name: {movie['name']}")
print(f"Director: {movie['director']}")
print(f"Release Year: {movie['year']}\n")
#continue
#break
def search_movies():
movies
print("This is where you'd see a list of movies in your database")
menu()
The problem is in your while user_input != 'Q': loop.
If user_input is equal to L, then it calls show_movies(), but doesn't ask for more input. It just goes round and round the while loop calling show_movies() each time.
You should input user_input again each time through the loop, not only in your else clause.
while user_input != 'Q':
if user_input == 'A':
add_movies()
elif user_input == 'L':
show_movies()
elif user_input == 'A':
search_movies()
else:
print("\n\n--Unknown command--Please try again.\n")
print("Welcome to 'The Movie Program!!'")
print("(A)dd movie to your list")
print("(L)ist movies you've added")
print("(S)earch for movies in your list")
# the next line is now outside your `else` clause
user_input = str(input("Which FUNCTION would you like to do?:\n\nSelection: ").capitalize())

Categories