Trying to create a program that determines discounts in a book shop, unsure about returning values from functions to main though, Help would be greatly appreciated
def main():
print (" Please enter the amount spent on the following items:")
Books = int(input("Books: "))
Magazines= int(input("Magazines: "))
Newspapers= int(input("Newspapers: "))
print (book_disc)
def discounts(Books, Magazines, Newspapers):
book_disc = Books - (Books *.2)
mag_disc = Magazines - (Magazines*.1)
news_disc = Newspapers
return discounts
return (book_disc, mag_disc, news_disc)
main()
Here's what I found:
You had some indentation issues
You are trying print (book_disc) before book_disc is defined (it's now been removed)
Your returns were out of order return (book_disc, mag_disc, news_disc) needed to be in your discounts() function
return discounts needed arguments
def main():
print (" Please enter the amount spent on the following items:")
Books = int(input("Books: "))
Magazines= int(input("Magazines: "))
Newspapers= int(input("Newspapers: "))
def discounts(Books, Magazines, Newspapers):
book_disc = Books - (Books *.2)
mag_disc = Magazines - (Magazines*.1)
news_disc = Newspapers
return (book_disc, mag_disc, news_disc)
return discounts(Books, Magazines, Newspapers)
main()
Related
class Budget:
def __init__(self):
self.wants_perc = 0
self.wants_amt = 0
self.wants_left = 0
self.needs_perc = 0
self.needs_amt = 0
self.needs_left = 0
self.food_perc = 0
self.food_amt = 0
self.food_left = 0
while True:
try:
self.monthly_income = float(input("Enter your monthly income after taxes: "))
break
except ValueError:
print("Invalid Input : Please enter a number")
continue
while True:
print("Enter desired percentage of income spent for each category (do not include %): ")
try:
self.wants_perc = float(input("Wants: "))
self.needs_perc = float(input("Needs: "))
self.food_perc = float(input("Food: "))
if self.wants_perc + self.needs_perc + self.food_perc not in range(95, 105):
print("Invalid Input : Must add to 100%")
continue
else:
break
except ValueError:
print("Invalid Input : Please enter a number")
continue
def deposit(self):
dep_loc = input("Where would you like to deposit? ")
while True:
try:
if dep_loc.lower() == "wants":
self.wdep_amt = float(input("Deposit amount: "))
self.wants()
break
elif dep_loc.lower() == "needs":
self.ndep_amt = float(input("Deposit amount: "))
self.needs()
break
elif dep_loc.lower() == "food":
self.fdep_amt = float(input("Deposit amount: "))
self.food()
break
else:
print("Invalid Input")
break
except ValueError:
print("Invalid Input : Please enter a number")
continue
def wants(self):
self.wants_max = (self.wants_perc / 100) * self.monthly_income
self.wants_amt += self.wdep_amt
self.wants_left = self.wants_max - self.wants_amt
print(f"Amount spent on wants: ${self.wants_amt} \nAmount left to spend: ${round(self.wants_left,2)}")
def needs(self):
self.needs_max = (self.needs_perc / 100) * self.monthly_income
self.needs_amt += self.ndep_amt
self.needs_left = self.needs_max - self.needs_amt
print(f"Amount spent on needs: ${self.needs_amt} \nAmount left to spend: ${round(self.needs_left,2)}")
def food(self):
self.food_max = (self.food_perc / 100) * self.monthly_income
self.food_amt += self.fdep_amt
self.food_left = self.food_max - self.food_amt
print(f"Amount spent on food: ${self.food_amt} \nAmount left to spend: ${round(self.food_left,2)}")
wyatt = Budget()
while True:
wyatt.deposit()
I know this is a very general question, but is it possible to reduce the amount of repeated code I use? I feel like there has to be a way to use one general variable in a loop for each of the categories. My three functions that use the food, wants, and needs variables are all the exact same besides the names. I thought of getting user input and adding it to a list and indexing that list to get each category, but I couldn't fully figure it out. This may be too broad for stack overflow and if it is I apologize. Thanks!
In general there is no mechanism for reducing the amount of code - if there was, it would already be part of the language. Making a dictionary instead of member variables doesn't really help, because all it will do is replace your 9 member variables with 9 dictionary items.
However, there is an opportunity for factoring out repeated operations. Your instinct is correct that repeated blocks of code are a sign of poor design. I would suggest you start with a class structure something like this:
class BudgetItem:
def __init__(self, name):
self.name = name
self.perc = 0
self.amt = 0
self.left = 0
def get_perc(self):
self.perc = float(input(f"{self.name}: "))
class Budget:
def __init__(self, monthly_income):
self.monthly_income = monthly_income
self.wants = BudgetItem("Wants")
self.needs = BudgetItem("Needs")
self.food = BudgetItem("Food")
self.all_items = (self.wants, self.needs, self.food)
def gather_percentages(self):
print("Enter desired percentage of income"
" spent for each category (do not include %): ")
for b in self.all_items:
b.get_perc()
if 95.0 <= sum(b.perc for b in self.all_items) <= 105.0:
print("Precentages must sum to 100")
# etc.
Create a separate class to represent a budget category, since the logic for each is identical. Add methods to the little class to capture that logic. Now re-write your main class in terms of those three individual items. I won't take the time to refactor your whole program, but I hope you get the idea. You should end up with a much shorter program and no significant repeated logic.
One other thing: I think that putting an "input" statement in a class constructor is a terrible idea. Constructors should not contain complicated loops or extended logic. I would put it outside the class and pass the data into the class as arguments, or as method calls.
am working on a restaurant project, and I need a hand :)
so the program will display the main dishes, and the user has to enter which dish he/she wants..
and then the choice will be taken and then added to the bill (dish name, price, num of items)...
so far I chose a dictionary so when the user enters 1 (key), the program will display Mashroum Risto...
this what've created:
dishes = {1 : ('Mashroum Risito', 3.950), 2 : ['Tomato Pasta', 2.250],3:['Spagehtie',4.850]}
now my question is how to get the dish name without the price (the price is 3.950) and extract it! and also how to get the price without the name so then I can send it into the bill function to calculate it? and if you have any suggestions please go ahead, because i don't know if using dictionary was the right choice
def MainDish():
dishes = {1 : ('Mashroum Risito', 3.950), 2 : ['Tomato Pasta', 2.250],3:
['Spagehtie',4.850]}
dishes.values
print("1. Mashroum Risito 3.950KD")
print("2. Tomato Pasta 2.250KD")
print("3. Spagehtie 4.850KD")
choice = eval(input('Enter your choice: '))
NumOfItem = eval(input('How many dish(es): '))
while(choice != 0):
print(dishes.get(choice)) #to display the item only without the
price
a = dishes.values()
recipient(a)
break
The way you have implemented it:
print (dishes[1][0]) #will give you name
print (dishes[1][1]) #will give you price
where [x][y]
x = key in the dict (input in your case)
y = element of the value in the dict (0 = name, 1=price in your case)
You should probably create the dictionary better as below:
Follow up question is not so clear but I think this is what you are after roughly. You will need to tweak the returns to your usage:
def MainDish():
NumOfItem = float(input('How many dish(es): '))
dish = list(dishes)[choice-1]
cost_of_dish = dishes[dish]
totalcost = cost_of_dish * NumOfItem
print (f"\n\tOrdered {NumOfItem}x {dish} at {cost_of_dish}KD each. Total = {totalcost}KD\n")
return dish, cost_of_dish, totalcost
dishes = {'Mashroum Risito': 3.950, 'Tomato Pasta': 2.250}
for key,val in dishes.items():
print (f"{list(dishes).index(key)+1}. {key}: {val}KD")
keepgoing = True
while keepgoing:
choice = int(input('Enter your choice: '))
if choice == 0:
keepgoing = False
break
else:
dish, cost_of_dish, totalcost = MainDish()
Using python I am trying to make it where the books in a text file display and the user can select a book and a quantity and do this in a loop. As they do this it is supposed to save it to a text file as a receipt and print it out when the user is done making their selections. This is what I've been able to accomplish so far.
cusName = input("What is your name?")
def main():
def menu():
print("Here is a list of items that we have:")
books_file= open("Books.txt","r")
lines = books_file.readlines()
aryBooks = []
for line in lines:
print(line)
bookChoice = input("Which book would you like?")
bookQty = input("You chose", bookChoice , "How many would you like?")
print ("Qty:", bookQty)
print ("Item:", bookChoice)
price = print ("Price:", book[2])
print ("SubTotal:", price * bookQty)
repeat = input("Would you like another item? Y or N")
receipt_file= open("receipt.txt","w")
lines = receipt_file.writelines()
for i in range(0,len(aryBooks)):
print(i + 1, aryBooks[i])
Try the code below:
def menu():
# Main loop for shopping
cart = {}
# Read books here
books = read_books()
while True:
# Loop until user does not want to shop any longer
print("Here is a list of items that we have:\n")
for book_num, (book_name, book_price) in books.items():
print(f'#{book_num}: {book_name} -- ${book_price}')
bookChoice = input("Which book would you like? (Please enter a number)\n")
# Make sure user enters the right number
try:
price = books[bookChoice][1]
except:
print('Sorry you chose the wrong number')
print()
continue
bookQty = int(input(f"You chose {books[bookChoice][0]}. How many would you like?\n"))
subtotal = price * bookQty
cart[books[bookChoice][0]] = (bookQty, subtotal)
print (f"Qty: {bookQty}")
print (f"Item: {books[bookChoice][0]}")
print (f"Price: {price}")
print (f"SubTotal: {subtotal}")
repeat = input("Would you like another item? Y or N\n")
# End loop if answer was No
if repeat.lower() == 'n' or repeat.lower == "no":
print(f'Your total was: {sum([y for x, y in cart.values()])}')
generate_receipt('receipt.txt', books, cart)
print('Have a good day!\n')
break
else:
print('Here is what you have thus far:')
for name, (qty, sub) in cart.items():
print(f'Name: {name} ; Qty: {qty} ; Subtotal: {sub}')
print()
def generate_receipt(path_to_receipt, books, cart):
# Generate receipt based on shopping cart
with open(path_to_receipt, 'a') as receipt_file:
for name, (qty, subtotal) in cart.items():
receipt_file.write(f'Qty: {qty} ; Item: {name}; Total: {sum([y for x, y in cart.values()])}; Subtotal: {subtotal}\n')
def main():
# Main loop that starts the shopping
cusName = input("What is your name?\n")
print(f'Hi {cusName}. Welcome to the bookstore!')
menu()
def read_books(path_to_books="Books.txt"):
# Read in the books from the file
with open(path_to_books, 'r') as f:
books = f.readlines()
books = [book.strip().split(',') for book in books]
books = {book_num: (book_name, int(book_price)) for book_num, book_name, book_price in books}
return books
if __name__ == '__main__':
main()
The output file might not be what you want but that can be fixed really easily.
My Books.txt is as follows:
15,Harry Potter,20
2,LOTR,25
I'm absolutely brand new to Python unit test. I need to use it for a project I have to submit. I sort of have an idea of where to begin, it looks like we basically put in test parameters to functions we have defined in our program and we enter the expected result. If the expected result is output, we get OK, otherwise we will get Failure, or an error.
So my problem is that I have multiple user inputs stored into variables that are within for loops or while loops. I don't know where to even begin with this to set test values in for them.
Here is all of my code:
studentTripExpenses = {}
def dictCreate(studentAmount):
for i in range(0, studentAmount):
studentName = input("What is the name of the student? ")
expenseList = []
print("Enter 'done' to move to the next student.")
while True:
expense = input("What is the cost of this expense? ")
if expense.lower() == 'done':
break
elif (float(expense) >= 0) or (float(expense) < 0):
expenseList.append(float(expense))
elif not expense.isdigit():
print("Please enter a number or enter 'done' to move on.")
studentTripExpenses[studentName] = expenseList
return studentTripExpenses
def studentCost(dct):
for i in dct:
#Variable for individual costs of student
personalCost = 0
#Determines the total cost for each student
for x in dct[i]:
personalCost = personalCost + x
#Sets each students value to their total cost to two decimal places
dct[i] = float("%.2f" % personalCost)
return dct
def amountsDue(expenseLst, studentAvgPrice):
#Runs through the dictionary of students and individual total trip costs
for key in expenseLst:
maxPerson = max(expenseLst, key=expenseLst.get)
costDifference = 0
#Determines who owes who how much money
if max(expenseLst.values()) > expenseLst[key]:
costDifference = studentAvgPrice-expenseLst[key]
if (costDifference < 0):
costDifference = costDifference * -1
print("%s owes %s $%.2f" % (key, maxPerson, costDifference))
def main():
numOfStudents = int(input("How many students are going on the trip? "))
studentCostDict = dictCreate(numOfStudents)
studentTripExpenses = studentCost(studentCostDict)
totalCost = 0
#Gets the total cost for all students
for key in (studentTripExpenses):
totalCost = totalCost + studentTripExpenses[key]
#Changes the total cost to 2 decimal places
totalCost = float("%.2f" % totalCost)
#Determines the average amount spent per student
avgCost = float("%.2f" % (totalCost/len(studentTripExpenses)))
amountsDue(studentTripExpenses, avgCost)
main()
You can use mocking, where you replace a function or class with a test-supplied version. You can do this with the unittest.mock() module.
In this case, you can patch the input() name in your module; instead of the built-in function, the mock object will be called:
from unittest import mock
from unittest import TestCase
import module_under_test
class DictCreateTests(TestCase):
#mock.patch('module_under_test.input', create=True)
def testdictCreateSimple(self, mocked_input):
mocked_input.side_effect = ['Albert Einstein', '42.81', 'done']
result = dictCreate(1)
self.assertEqual(result, {'Albert Einstein': [42.81]})
Because input doesn't exist in your module (it is a built-in function), I told the mock.patch() decorator to create the name; now this input will be used instead of the built-in function.
The side_effect attribute lets you state multiple results; each time the mock is called, it'll return the next value in that list. So the first time 'Albert Einstein' is returned, the next time '42.81', etc.
Together, this lets you simulate actual user inputs.
If you do your test right, you'll notice that there is a bug in your function; the float() call will throw a ValueError exception when anything other than done or a valid numeric value is entered. You need to rework your code to account for that. Try with mocked_input.side_effect = ['Albert Einstein', 'Not an expense', '42.81', 'done'] to trigger the bug.
In case we do not have classes.
In the names.py file, we have the get_names function.
def get_names() -> list:
names = [str(input("Enter name: "))]
while str(input("Do you want to add another name")) == "Y":
names.append(str(input("Enter name: ")))
return categories
In the test_names.py file, we can write test like the following
import numpy as np
from unittest import mock
from src.main.names import get_names
#mock.patch('src.main.names.input', create=True)
def test_should_get_names_from_users(mocked_input):
mocked_input.side_effect = ["John", "Y", "Robert", "N"]
actual_names = get_names()
expected_names = ['John', "Robert"]
assert actual_names == expected_names
My goal is to have a small program which checks if a customer is approved for a bank loan. It requires the customer to earn > 30k per year and to have atleast 2 years of experience on his/her current job. The values are get via user input. I implemented regexs to validate the input to be only digits without any strigns or negatives, nor 0.
But the 3rd function asses_customer is always executing the else part. I think everytime the parameters are either None, either 0
here's the source code:
import sys
import re
import logging
import self as self
class loan_qualifier():
# This program determines whether a bank customer
# qualifies for a loan.
def __init__(self): #creates object
pass
def main():
salary_check()
work_exp_check()
asses_customer(salary = 0, years_on_job = 0)
def salary_check():
input_counter = 0 # local variable
# Get the customer's annual salary.
salary = raw_input('Enter your annual salary: ')
salary = re.match(r"(?<![-.])\b[1-9][0-9]*\b", salary)
while not salary:
salary = raw_input('Wrong value. Enter again: ')
salary = re.match(r"(?<![-.])\b[1-9][0-9]*\b", salary)
input_counter += 1
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
else:
return salary
def work_exp_check():
input_counter = 0 #local variable to this function
# Get the number of years on the current job.
years_on_job = raw_input('Enter the number of ' +
'years on your current job: ')
years_on_job = re.match(r"(?<![-.])\b[1-9][0-9]*\b", years_on_job)
while not years_on_job:
years_on_job = raw_input('Wrong work experience. Enter again: ')
years_on_job = re.match(r"(?<![-.])\b[1-9][0-9]*\b", years_on_job)
input_counter += 1
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
else:
return years_on_job
def asses_customer(salary, years_on_job):
# Determine whether the customer qualifies.
if salary >= 30000.0 or years_on_job >= 2:
print 'You qualify for the loan. '
else:
print 'You do not qualify for this loan. '
# Call main()
main()
You have stated:
It requires the customer to earn > 30k per year and to have at least 2 years of experience on his/her current job.
We can write some simple statements that request a number and if a number is not given then ask for that number again.
The following code is a very simple approach to achieving that goal.
class Loan_Checker():
def __init__(self):
self.salary = 0
self.years_on_job = 0
self.request_salary()
self.request_years()
self.check_if_qualified()
def request_salary(self):
x = raw_input('Enter your annual salary: ')
try:
self.salary = int(x)
except:
print("Please enter a valid number")
self.request_salary()
def request_years(self):
x = raw_input('Enter the number of years on your current job: ')
try:
self.years_on_job = int(x)
except:
print("Please enter a valid number")
self.request_years()
def check_if_qualified(self):
if self.salary >= 30000 and self.years_on_job >= 2:
print 'You qualify for the loan. '
else:
print 'You do not qualify for this loan. '
Loan_Checker()
You have a few errors in your code, and I've refactored it to use the class structure you seemed to want to imply.
import sys
import re
import logging
class loan_qualifier():
# This program determines whether a bank customer
# qualifies for a loan.
def __init__(self): #creates object
self.salary = self.salary_check()
self.years_on_job = self.work_exp_check()
def salary_check(self):
input_counter = 0 # local variable
# Get the customer's annual salary.
salary = None
while salary is None:
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
elif input_counter >= 1:
print ("Invalid salary.")
salary = raw_input('Enter your salary: ')
salary = re.match(r"(?<![-.])\b[1-9][0-9]*\b", salary).group(0)
input_counter += 1
# broke out of loop, so valid salary
return salary
def work_exp_check(self):
input_counter = 0 #local variable to this function
# Get the number of years on the current job.
years_on_job = None
while years_on_job is None:
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
elif input_counter >= 1:
print ("Invalid year amount")
years_on_job = raw_input('Enter the number of years at your current job: ')
years_on_job = re.match(r"(?<![-.])\b[1-9][0-9]*\b", years_on_job).group(0)
input_counter += 1
# broke out of loop, so valid years_on_job
return years_on_job
def assess_customer(self):
# Determine whether the customer qualifies.
if int(self.salary) >= 30000.0 and int(self.years_on_job) >= 2:
print 'You qualify for the loan. '
else:
print 'You do not qualify for this loan. '
if __name__ == "__main__":
lq = loan_qualifier()
lq.assess_customer()
Some of the errors fixed include the way you were calling assess_customer initially (you were assigning 0's to both values in the function call), as well as the spelling of assess :p. Your condition in assess_customer should also have been an and instead of an or (you wanted both conditions to be true for them to qualify, not for either condition to be true).
You actually don't even really need to do the:
self.salary = self.salary_check()
self.years_on_job = self.work_exp_check()
lines. You could just directly assign the class variables in the functions (i.e. instead of returning, just set self.salary = blah in salary_check). That's kind of a personal choice thing though. I think this makes it clear.
Hopefully this is all clear to you. Let me know if you have any questions. The code can be called by simply typing python NAME_OF_YOUR_FILE.py.
Edit: I didn't realize how broken the salary and years checks were, the new code should fix them.
Edit: Fixed the regex results in this version. My bad.
In this fragment you pass third function always salary = 0 and years_on_job = 0
Try this way:
salary = salary_check()
years_on_job = work_exp_check()
asses_customer(salary, years_on_job)