def main():
def load():
name=0
count=0
totalpr=0
name=input("Enter stock name OR -999 to Quit: ")
while name != '-999':
count=count+1
shares=int(input("Enter number of shares: "))
pp=float(input("Enter purchase price: "))
sp=float(input("Enter selling price: "))
commission=float(input("Enter commission: "))
name = input("Enter stock name OR -999 to Quit: ")
def calc():
amount_paid=shares*pp
commission_paid_purchase=amount_paid*commission
amount_sold=shares*sp
commission_paid_sale=amount_sold*commission
profit_loss=(amount_sold - commission_paid_sale) -(amount_paid + commission_paid_purchase)
totalpr=totalpr+profit_loss
def print():
print("\nStock Name:", name)
print("Amount paid for the stock: $", format(amount_paid, '10,.2f'))
print("Commission paid on the purchase: $", format(commission_paid_purchase, '10,.2f'))
print("Amount the stock sold for: $", format(amount_sold, '10,.2f'))
print("Commission paid on the sale: $", format(commission_paid_sale, '10,.2f'))
print("Profit (or loss if negative): $", format(profit_loss, '10,.2f'))
print("Total Profit is $", format(totalpr, '10,.2f'))
return main()
load() #to input the values
calc()
print()
I'm not sure what I'm doing wrong:
Should I be putting in variable names into def load():, def calc(): and def print():?
As I run it now, it says "load" is not defined. How would I go about defining load? And for that matter, if I didn't define def calc(): and def print(): how do I define those?
I do properly call them at the end of the code, in the order that I'd like to call them -- load, calc, and then print.
Is my "return main()" the right thing to do? I don't know, I Just want this code to run properly without error that's all. I'm under the impression that I'm just missing a few things. Any help would be appreciated.
You are defining load() inside the scope of main(). This means you cannot use the function outside of main().
The easy solution is that you should put your function defines for load, calc, and print outside of the definition of main() (btw, call it something else like print_stock info, print is already a function!)
You also do not need to return main(). I am unsure what you are trying to do, but it is not necessary at all.
yikes.
your first mistake: calling a function in another function. Maybe you meant to do
class Main:
def load(self):
#do a thing
then you'd have to do
main = Main()
main.load()
your second mistake was defining a new a print() function that uses print functions, as one already exists. Rename it, as that will cause a huge error
This is a minimal working example to illustrate how one can solve what you are trying to do.
# helper for interpreting input
import ast
#: initial starting values
thing, count, cost, total = 'Nothing', 0, 0, 0
# define all functions at module indentation
def get_user_input():
global thing, count, cost # write to the GLOBAL names thing, count and cost
thing = input('What have you?') # ask for a string
count = ast.literal_eval(input('How much do you have?')) # ask for a string and interpret it: "3.2" => float
cost = ast.literal_eval(input('How much does each cost?'))
def compute():
global total # write to global name total
total = count * cost # can read from global names
def pretty_print(): # not named print! we still need print to print!
print("You have", count, thing)
print("At", cost, "each, that makes", total, "in total")
# call functions at module indentation
get_user_input() # ducks, 3, 42
compute()
pretty_print()
# You have 3 ducks
# At 42 each, that makes 126 in total
One thing to warn you about: working with global variables is generally a bad idea. For a small script it's fine, but you've already messed up the basics - globals are tricky, so avoid them whenever possible. If you just want to run these commands, do not write them as functions, execute them directly. Basically, leave away the def ... and global ... lines and put everything on the same indentation, then remove the last three lines.
If you really want to store and print multiple things, you need to use containers. Just assigning to a value in a loop, e.g. thing = input('What have you?'), will leave it at the last value entered. Instead, you need a container like a list. You can then append additional values to it.
container = [] # [] is a list literal
for _ in range(3): # non-infinite loop
next_thing = ast.literal_eval(input('Place your order...\n'))
container.append(next_thing)
print("You ordered", container)
def load():
global name
global count
global shares
global pp
global sp
global commission
name=input("Enter stock name OR -999 to Quit: ")
count =0
while name != '-999':
count=count+1
shares=int(input("Enter number of shares: "))
pp=float(input("Enter purchase price: "))
sp=float(input("Enter selling price: "))
commission=float(input("Enter commission: "))
calc()
display()
name=input("\nEnter stock name OR -999 to Quit: ")
def calc():
global amount_paid
global amount_sold
global profit_loss
global commission_paid_sale
global commission_paid_purchase
global totalpr
totalpr=0
amount_paid=shares*pp
commission_paid_purchase=amount_paid*commission
amount_sold=shares*sp
commission_paid_sale=amount_sold*commission
profit_loss=(amount_sold - commission_paid_sale) -(amount_paid + commission_paid_purchase)
totalpr=totalpr+profit_loss
def display():
print("\nStock Name:", name)
print("Amount paid for the stock: $", format(amount_paid, '10,.2f'))
print("Commission paid on the purchase: $", format(commission_paid_purchase, '10,.2f'))
print("Amount the stock sold for: $", format(amount_sold, '10,.2f'))
print("Commission paid on the sale: $", format(commission_paid_sale, '10,.2f'))
print("Profit (or loss if negative): $", format(profit_loss, '10,.2f'))
def main():
load()
main()
print("\nTotal Profit is $", format(totalpr, '10,.2f'))
Related
How can I fix the inputs? Because they do not show up when I run my program.
## Define the main module
def main():
## Initialize local Variables / Set Constant
homeValue = 0
propertyTaxRate = 0
bedrooms = 0
BEDROOMSURCHARGERATE = 0.0025
## Set initialized varialbes to user inputs
homeValue = float(input("How much is your home worth?"))
propertyTaxRate = float(input("What is your Property Tax Rate entered as a decimal?"))
bedrooms = int(input("How many bedrooms will your house have?"))
## Set Variables equal to results of module outputs
propertyTax = getPropertyTax(homeValue, propertyTaxRate)
bedroomSurcharge = getBedroomSurcharge(BEDROOMSURCHARGERATE, bedrooms, homeValue)
totalPropertyTax = getTotalPropertyTax(propertyTax, bedroomSurcharge)
## Report All information with a propertyTaxReport
propertyTaxReport(homeValue, propertyTaxRate, bedrooms, propertyTax, bedroomSurcharge, totalPropertyTax)
## Define getPropertyTax Module
def getPropertyTax(homeValue, propertyTaxRate):
## Calculate property tax
propertyTax = homeValue*propertyTaxRate
return propertyTax
## Define getBedroomSurcharge
def getBedroomSurcharge(BEDROOMSURCHARGERATE, bedrooms, homeValue):
## Calculate Bedroom Surcharge
bedroomSurcharge = BEDROOMSURCHARGERATE*bedrooms*homeValue
return bedroomSurcharge
## Define getTotalPropertyTax
def getTotalPropertyTax(propertyTax, bedroomSurcharge):
## Calculate totalProperty Tax
totalPropertyTax = propertyTax + bedroomSurcharge
return totalPropertyTax
## Define propertyTaxReport
def propertyTaxReport(homeValue, propertyTaxRate, bedrooms, propertyTax, bedroomSurcharge, totalPropertyTax):
## Output Variables
print("Your home costs ", homeValue, " dollars.")
print("Your property tax rate is ", propertyTaxRate)
print("Your house has ", bedrooms, "bedrooms")
print("Your property tax is equal to ", propertyTax, " dollars.")
print("Your bedroom surcharge is equal to ", bedroomSurchage, " dollars")
print("Your total property tax comes out to ", totalPropertyTax, " dollars")
return
I think you are drying a bit with your code.
A few suggestions:
You do not need to initialise a variable if this is an input from the user.
If you can simplify a calculation, just do it. Do not create many functions if they are not necessary.
You do not to print as output variables that the user gives as input. I guess the user already knows that. But if it is a serious report, maybe I can give you that.
Try this and let me know:
def main_function():
BEDROOMSURCHARGERATE = 0.0025
## Set initialized variables to user inputs
homeValue = float(input("How much is your home worth?"))
propertyTaxRate = float(input("What is your Property Tax Rate entered as a decimal?"))
bedrooms = int(input("How many bedrooms will your house have?"))
## Set Variables equal to results of module outputs
propertyTax = homeValue*propertyTaxRate
bedroomSurcharge = BEDROOMSURCHARGERATE*bedrooms*homeValue
totalPropertyTax = propertyTax + bedroomSurcharge
## Report all information with a propertyTaxReport
return (totalPropertyTax, f"bedroom Surcharge was {bedroomSurcharge}")
To call the function just do:
main_function()
You can return this tuple or print the whole thing you have at the end, up to you. I just point out that you can return just a value or a sentence.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 months ago.
Improve this question
I don't know how functions work and would like help making sure that I can have the variable change depending on which 'person' is running the account. Can someone explain how to change the 'bad' variable so that it goes to a 'person 1' 'person 2' or 'person 3' depending on which the user chooses to enter?:
bal=500
lock=0
end=False
def atm():
while end==False:
if lock>=4:
while lockloop==True:
try:
print("Your balance is $",bal, sep='')
lk=int(input("Error, you have locked your account. Please enter funds until balance becomes positive: \n$"))
if lk<=0:
print("Please input a positive amount")
continue
bal=bal+lk
if bal<0:
continue
except ValueError:
print("Try again")
continue
else:
lockloop=False
lk=0
lock=0
print("Your balance is now: $", bal, sep='')
des=input("Would you like to (d)eposit, (w)ithdraw, (b)alance, or (e)nd? ")
witloop=True
deploop=True
lockloop=True
if lock>1 and bal>=0:
lock=1
if des=="deposit" or des=="d" and lock<4:
while deploop==True:
try:
dep=int(input("How much would you like to deposit? "))
if dep<=0:
print("Please input a positive amount")
continue
except ValueError:
print("Try again")
continue
else:
deploop=False
bal=dep+bal
dep=0
if bal<0 and lock==0:
bal=bal-50
lock=lock+1
print("You have incured an overdraft fee of $50. It will be removed from your account.")
if bal<0 and lock!=0:
lock=lock+1
print("Your account is still overdrawn. Please deposit funds.")
print("You now have: $", bal, sep='')
continue
elif des=="withdraw" or des=="w" and lock<4:
if bal<=0:
print("Cannot withdraw funds at this time.")
continue
while witloop==True:
try:
wit=int(input("How much would you like to withdraw? "))
if wit<=0:
print("Please input a positive amount")
continue
except ValueError:
print("Try again")
continue
else:
witloop=False
bal=bal-wit
wit=0
if bal<0 and lock==0:
bal=bal-50
lock=lock+1
print("You have incured an overdraft fee of $50. It will be removed from your account.")
if bal<0 and lock!=0:
lock=lock+1
print("Your account is still overdrawn. Please deposit funds.")
print("You now have: $", bal, sep='')
continue
elif des=="balance" or des=="b":
print("You have: $", bal, sep='')
continue
elif des=="end" or des=="e" and lock==0:
end=True
print("Thank you for banking with Nolan's Banking Services today! Have a great day! :)")
else:
print("You must enter one of the four options, try again")
continue
atm()
Running your code as-is is returning this error:
UnboundLocalError: local variable 'end' referenced before assignment
The reason here is to do with the scope of your variables. You are declaring the bal, lock and end variables outside of your function, therefore making them global variables. But you are also then declaring those variables inside the function, making them local variables. The interpreter is getting confused and the error is telling you the the local variable end is being used before it is being assigned.
Don't mix and match variables inside and outside a function like this. You should try to avoid global variables in your functions as much as possible as a good rule of thumb when programming.
You could read some more here as a starting point:
https://www.w3schools.com/python/python_variables_global.asp
https://bobbyhadz.com/blog/python-unboundlocalerror-local-variable-name-referenced-before-assignment
I don't know how to have the function use a different variable for each person
You can pass arguments into your function like this. In this case, when we define the function, we tell it to expect an argument called user that you can then use inside your function.
def atm(user):
if user == 'Nolan':
print('Hi Nolan')
elif user == 'Lummers':
print('Hi Lummers')
else:
print("I don't talk to strangers")
atm('Nolan')
atm('Lummers')
atm('John Doe')
To provide a different variable for each person I suggest you look into classes. Something like ...
class Person:
def __init__(self, name: str, balance: float = 0):
"""Create a new person each time."""
self.name = name
self.balance = balance
def action(self, action: str, amount: float):
if action == 'deposit':
self.balance += amount
elif action == 'withdraw':
self.balance -= amount
def __repr__(self):
return f"{self.name} {self.balance}"
def main():
customers = {}
customers['Fred'] = Person('Fred', 500)
customers['Jane'] = Person('Jane')
"""Preload some actions for example."""
actions = [
['Fred', 'withdraw', 123],
['Jane', 'deposit', 789]
]
"""Process the actions. Could run forever."""
for person, action, value in actions:
if person in customers:
customers[person].action(action, value)
print(customers)
if __name__ == '__main__':
main()
As an assignment I am making a simple interface in python which can show a balance, add to that balance, take out money from that balance, check the interest rate and then lastly check the three previous actions done. This will be choice == 5. So what do I write in the bottom def in order to do so?
usd = 500
def main():
print("""
1. Balance
2. Add
3. Retrieve
4. Interest
5. Last Changes
""")
choice = int(input("Choose: "))
if choice == 1:
global usd
balance()
elif choice == 2:
add()
elif choice == 3:
retrieve()
elif choice == 4:
interest()
elif choice == 5:
changes()
def balance():
global usd
print("Balance: ", round((usd),2))
main()
def add():
global usd
amount = int(input("How much do you want to add? "))
usd = amount + usd
print("New balance = ", round((usd),2))
main()
def retrieve():
global usd
amount = int(input("How much do you want to retrieve: "))
usd = usd - amount
print("New balance = ", round((usd),2))
main()
def interest():
global usd
if usd<=1000000:
usd = ((usd/100)*101)
print("New balance: ", round(((usd/100)*101), 2))
elif usd>=1000000:
usd = ((usd/100)*102)
print("New balance: ", round(((usd/100)*102), 2))
main()
def changes():
main()
main()
The desired output will look a little like this;
Choose: 5
+6105
-500000
+1110000
It sounds like you want to keep a log of the previous actions. You could do this by creating a list and appending a new entry each time an action is done. Then your changes function could print out the last 3 items in the list.
You could make the list global and access it in the same way you access usd.
You could also make the list in main and pass it to changes as an argument. If you decide to do it this way, you could make each function return their log so that you can append it to the list in main.
For example (using only the add function illustrate)
Using a global variable (this is bad practice, but is shorter):
usd = 500
log = []
def add():
global usd
amount = int(input("How much do you want to add? "))
usd = amount + usd
print("New balance = ", round((usd),2))
log.append(f"+{amount}") # add change to log
main()
def changes():
# print last 3 items in log
for change in log[-3:]:
print(change)
main()
Or the more typical way, using a loop (without a global variable)
usd = 500
def main():
log = []
choice = 0
while choice != 6:
print("""
1. Balance
2. Add
3. Retrieve
4. Interest
5. Last Changes
6. Quit
""")
choice = int(input("Choose: "))
if choice == 1:
balance()
elif choice == 2:
log.append(add()) # add change to log
elif choice == 3:
log.append(retrieve()) # add change to log
elif choice == 4:
interest()
elif choice == 5:
changes(log)
def add():
global usd
amount = int(input("How much do you want to add? "))
usd = amount + usd
print("New balance = ", round((usd),2))
return f"+{amount}"
def changes(log):
# print last 3 items in log
for change in log[-3:]:
print(change)
main()
A potential problem with this approach is because you are adding items to the log list indefinitely, theoretically you may eventually run out of memory on your computer. To remedy, you can remove extra logs from the list whenever the length of the list is greater than 3.
Documentation for lists: https://docs.python.org/3/tutorial/datastructures.html
Global variables are bad practice in general, so it would be preferable to avoid making usd a global variable, but I'll leave that up to you
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
def main():
totalprofit = 0
stockname = input("Enter the name of the stock or -999 to quit: ")
while stockname != "-999":
sharesbought, purchasingprice, sellingprice, brokercommission = load()
amountpaid, amountofpaidcommission, amountstocksoldfor, amountofsoldcommission, profitorloss = calc(sharesbought, purchasingprice, sellingprice, brokercommission)
output(stockname, amountpaid, amountofpaidcommission, amountstocksoldfor, amountofpaidcommission, profitorloss)
stockname = input("Enter the name of the next stock (or -999 to quit): ")
totalprofit += profitorloss
print("\n Total profit is: ", format(totalprofit, '.2f'))
def load():
sharesbought = int(input("Number of shares bought: "))
purchasingprice = float(input("Purchasing price: "))
sellingprice = float(input("Selling price: "))
brokercommission = float(input("Broker commission: "))
return sharesbought, purchasingprice, sellingprice, brokercommission
def calc(sharesbought, purchasingprice, sellingprice, brokercommission):
amountpaid = sharesbought * purchasingprice
amountofpaidcommission = amountpaid * (brokercommission/100)
amountstocksoldfor = sharesbought * sellingprice
amountofsoldcommission = amountstocksoldfor * (brokercommission/100)
profitorloss = (amountpaid + amountofpaidcommission) - (amountstocksoldfor - amountofsoldcommission)
return amountpaid, amountofpaidcommission, amountstocksoldfor, amountofsoldcommission, profitorloss
def output(stockname, amountpaid, amountofpaidcommission, amountstocksoldfor, amountofsoldcommission, profitorloss,):
print("\n Stock name: ", stockname, sep = '')
print("Amount paid for the stock: ", format(amountpaid, '.2f'))
print("Commission paid to broker when the stock was bought: ", format(amountofpaidcommission, '.2f'))
print("Amount the stock sold for: ", format(amountstocksoldfor, '.2f'))
print("Commission paid to broker when the stock was sold: ", format(amountofsoldcommission, '.2f'))
print("Profit or loss: ", format(profitorloss, '.2f'))
main ()
The objective of the first function is to allow a user to input the followings as many times as she or he wants until the user decides is done:
Stock name
Shares bought
Selling price
Broker commission
My main problem is then in the main function. I am skeptical whether I am using the while loop correctly or if it's correct at all. I tried to run the program but it won't output anything.
Also, shouldn't I add this at the end of the program with the values inputted to call all the functions above:
def main()
load()
calc()
output()
Or is it fine within the while loop?
I think a while loop is perfectly appropriate for this use case, where you want to loop an indeterminate number of times, stopping when some condition is not met.
There is one obvious problem, on this line:
stockname +=1
This doesn't make any sense. Since stockname is a string, you can't add one to it. Instead, you should be asking the user for the next stock name (or a "special" value to signal they're done). Try replacing that line with something like:
stockname = input("Enter the name of the next stock (or -999 to quit): ")
The rest of your code appears correct, if rather verbose. Unless you think it's likely you'll call some of your other functions in some other place in your code, it might be simpler and cleaner to include all the logic in one function. Functions are nice, but you should balance the benefits of isolating each part of your code in its own function against the effort of passing lots of values between them.