OK - I am trying to get a Python function to accept variables from two other functions. Is this possible ?
A sample of what I am trying to do it below (I have simmed down the original code - for input here). Hopefully you get theidea of what I am trying to do. In a nutshell, I have Rectangle () which calls Extras() and the I want the output from Rectangle and Extras to be sent to the Calculate_Deposit ().
Is this possible ?
def calculate_deposit(total_cost, extras):
deposit_percent = float(raw_input("Enter Deposit % (as a decimal) of Total Cost: "))
months_duration = float(raw_input("Enter the number of months client requires: "))
if deposit_percent >0:
IN HERE JUST SOME CALCULATIONS
else:
print "The total amount required is: ", total_cost
def rectangle(width, height, depth, thickness):
type = raw_input("Enter lowercase c for concrete: ")
if type == 'c':
output = IN HERE JUST COME CALCULATIONS
else:
return raw_input("Oops!, something went wrong")
print output + extras()
total_cost = calculate_deposit(output, extras)
def extras():
type = float(raw_input("Enter 1 for lights: "))
if type == 1:
light = 200
print "The cost of lights are: ", light
return light
else:
return raw_input("No extras entered")
In rectangle, you call extras(), then you send just the function extras to calculate_deposit(). You want to send the result of the extras() call, not a reference to the function itself. You can make a minor change and save that value, referring to it when you print and when you go into calculate_deposit.
Change this:
print output + extras()
total_cost = calculate_deposit(output, extras)
To this:
extra = extras()
print output + extra
total_cost = calculate_deposit(output, extra)
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.
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
I have been trying to figure out how to pass data between functions, I'm new to coding. I have tried multiple way to do it, I am struggling to understand how data is passed my code is below. Help would be awesome.
x = []
y = []
z = []
def w(): #Welcome greeting the user and asking for their name
print("Welcome to the BMI Index Calculator.")
name = input("Enter employee's name or Exit to quit: ") # Allows the user to input there name as a variable
if str.isnumeric(name): # Test as a string
print("That is not a name.")
w()
if name == 'Exit': # sets the Exit for the program
print("Exiting program...")
exit() # ends program
else:
name = x.append(name)
def h():
height = input("Enter employee's height in inches: ")
if height == '0': # sets the Exit for the program
print("Exiting program...")
exit() # ends program
else:
height = y.append(height)
def wt():
weight = input("Enter employee's weight in lbs: ")
if weight == '0': # sets the Exit for the program
print("Exiting program...")
exit() # ends program
else:
weight = z.append(weight)
def bmi(): #gives the data back to the user
print(str(x).replace('[', '').replace(']', '').replace("'", '') + "'s " + "BMI profile")
print("---------------------------")
print("Height: ", str(y).replace('[', '').replace(']', '').replace("'", ''), '"')
print("Weight: ", str(z).replace('[', '').replace(']', '').replace("'", ''), "lbs.")
def math_cal():
bmi_weight = int(z) * 703
bmi_height = int(y) ** 2
print("BMI: ", bmi_weight / bmi_height)
def run():
x = w()
y = h()
z = wt()
xy = bmi()
xz = math_cal()
__main__()
run()
__main__()
I have been successful in passing the data to other functions but the code fails to see the list as an int. Thus I have found my way here, trying to get ideas of how to rewrite this code in a more efficient manner. I am looking for a way to reference functions to pass data between functions, however I have not been find a clean way to execute that process.
There are to points where values are passed when using functions:
at the start of the function, with parameters
at the end of the function, as return value
let us first take a look at the return value:
For example in your h() function, you ask the user for the height. This value is stored in height
height = input("Enter employee's height in inches: ")
after checking for all the cases you want, you can return one value at the end of the function by using "return":
return height
the complete function becomes:
def h():
height = input("Enter employee's height in inches: ")
if height == '0': # sets the Exit for the program
print("Exiting program...")
exit() # ends program
return height
This means if you call the function h() it will ask for the height and return the value which it obtained. This could be used by you program like this:
bmi_height = h()
or
bmi_height = h()*2
if you want to multiply the entered value with 2.
The second part, passing values to a function at the start of the function with parameters:
for example you want to use the height and weight when calculating the BMI, then the function becomes:
def bmi(height, weight)
print("BMI: ", bmi_weight / bmi_height)
this function has to be called like this:
bmi(170, 85)
when entering the values hard-coded or
height = 170
weight = 85
bmi(height, weight)
when you use variables.
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)
Here is my code:
# This program makes the robot calculate the average amount of light in a simulated room
from myro import *
init("simulator")
from random import*
def pressC():
""" Wait for "c" to be entered from the keyboard in the Python shell """
entry = " "
while(entry != "c"):
entry = raw_input("Press c to continue. ")
print("Thank you. ")
print
def randomPosition():
""" This gets the robot to drive to a random position """
result = randint(1, 2)
if(result == 1):
forward(random(), random())
if(result == 2):
backward(random(), random())
def scan():
""" This allows the robot to rotate and print the numbers that each light sensors obtains """
leftLightSeries = [0,0,0,0,0,0]
centerLightSeries = [0,0,0,0,0,0]
rightLightSeries = [0,0,0,0,0,0]
for index in range(1,6):
leftLight = getLight("left")
leftLightSeries[index] = leftLightSeries[index] + leftLight
centerLight = getLight("center")
centerLightSeries[index] = centerLightSeries[index] + centerLight
rightLight = getLight("right")
rightLightSeries[index] = rightLightSeries[index] + rightLight
turnRight(.5,2.739)
return leftLightSeries
return centerLightSeries
return rightLightSeries
def printResults():
""" This function prints the results of the dice roll simulation."""
print " Average Light Levels "
print " L C R "
print "========================="
for index in range(1, 6):
print str(index) + " " + str(leftLightSeries[index]) + " " + str(centerLightSeries[index]) + " " + str(rightLightSeries[index])
def main():
senses()
pressC()
randomPosition()
scan()
printResults()
main()
So, I am getting this error when I run my program.
NameError: global name 'leftLightSeries' is not defined
I understand that I must be doing something wrong related to the return statement. I'm not sure if I can only return one variable at the end of a user-defined function. If that were to be true, then I should probably separate the scan(): function. Anyways, I would appreciate any help on how to fix this error. Also, this is the result that I am looking for when I successfully complete my program:
Click Here
I am looking to complete the average values like the picture shows, but I am not worried about them at this point, only the list of values from the light sensors. I do not need to reach those exact numbers, the numbers will vary in the simulator.
If you want to return multiple items from scan(), don't use three separate return statements. Instead, do this:
return leftLightSeries, centerLightSeries, rightLightSeries
Also, when you call the function, you have to assign variable(s) to the returned values; it won't automatically create new local variables with the same names. So in main, call scan() like this:
leftLightSeries, centerLightSeries, rightLightSeries = scan()