Need help simplifying my script in Python - python

I am new to programming Python, learning mostly through "learn python the hard way." I recently wrote a script that will help me calculate the overtime earnings for my piece work employees. The script works, but it just doesn't look right to me. I would love input on how I could have saved myself some steps. I know using globals is taboo, but I could not figure out another way to get the answers outside those functions. Thank you!!
# THIS SCRIPT WILL CALCULATE THE NUMBER OF PAID HOURS, OVERTIME HOURS, PIECE RATE HOURS AND OVERTIME HOURS OWED TO AN EMPLOYEE.
number_of_straight_hours_worked = False
number_of_overtime_hours_worked = False
employee_travel_time = False
days_worked = False
employee_earnings = False
employee_hourly_rate = False
employee_overtime_rate = False
#Function to determine number of straight hours worked.
def straight_hours():
global number_of_straight_hours_worked
number_of_straight_hours_worked = float(number_of_straight_hours_worked)
while number_of_straight_hours_worked == False:
number_of_straight_hours_worked = raw_input("How many straight hours did the employee work? ")
try:
int(number_of_straight_hours_worked)
except ValueError:
print("Must use a number")
number_of_straight_hours_worked = False
else:
print ("Thank you.")
#print number_of_straight_hours_worked
# Determines number of overtime hours.
def overtime_hours():
global number_of_overtime_hours_worked
number_of_overtime_hours_worked = float(number_of_overtime_hours_worked)
while number_of_overtime_hours_worked == False:
number_of_overtime_hours_worked = raw_input("How many overtime hours did the employee work? ")
try:
int(number_of_overtime_hours_worked)
except ValueError:
print("Must use a number")
number_of_overtime_hours_worked = False
else:
print ("Thank you.")
#print number_of_overtime_hours_worked
#Calcualtes the employee's overtime rate.
def employee_ot_calculation():
global employee_hourly_rate
global employee_overtime_rate
while employee_hourly_rate == False:
employee_hourly_rate = raw_input("What is the employee's hourly rate? ")
try:
float(employee_hourly_rate)
except ValueError:
print("Must use a number.")
#print employee_hourly_rate
else:
employee_overtime_rate = float(employee_hourly_rate) * 1.5
#Stores travel time hours
def travel_time():
global employee_travel_time
while employee_travel_time == False:
employee_travel_time = raw_input("How many hours of travel? ")
try:
int(employee_travel_time)
except ValueError:
print("Must use a number.")
employee_travel_time = False
else:
print ("Thank you.")
#print employee_travel_time
#Stores number of working days. Not used in version .001
def number_of_days_worked():
global days_worked
while days_worked == False:
days_worked = raw_input("How many days did the employee work? ")
days_worked = float(days_worked)
try:
int(days_worked)
except ValueError:
print("Must use a number.")
days_worked = False
else:
print ("Thank you.")
#Stores earnings made by piece work from employee.
def employee_piece_earnings():
global employee_earnings
while employee_earnings == False:
employee_earnings = raw_input("What did the employee earn through piece rate (format: 0.00)? ")
employee_earnings = float(employee_earnings)
try:
float(employee_earnings)
except ValueError:
print("Must use a number, no dollar sign.")
employee_earnings = False
else:
print ("Thank you.")
#print employee_earnings
# Calculates what the employee will earn this pay period between hours and piece work.
def overtime_piece():
total_hours_worked = float(number_of_straight_hours_worked) + float(number_of_overtime_hours_worked)
# print total_hours_worked
actual_working_hours = float(total_hours_worked) - float(employee_travel_time)
#print actual_working_hours
piece_overtime = float(actual_working_hours) - 40
#print piece_overtime
overtime_rate = float(employee_earnings / actual_working_hours)
#print overtime_rate
earned_straight_pay = float(number_of_straight_hours_worked) * float(employee_hourly_rate)
print "This employee earned $%.2f in straight pay: %.2f hours at $%.2f per hour" % (earned_straight_pay, number_of_straight_hours_worked, employee_hourly_rate)
earned_hourly_overtime = (float(total_hours_worked) - float(actual_working_hours)) * float(employee_overtime_rate)
print "This employee earned $%.2f in hourly overtime: %.2f hours at $%.2f per hour" % (earned_hourly_overtime, number_of_overtime_hours_worked, employee_overtime_rate)
earned_piece_overtime = float(overtime_rate) * float(piece_overtime)
print "This employee earned $%.2f in piece OT: %2f for each of working hour of the %.2f hours of overtime" % (earned_piece_overtime, overtime_rate, piece_overtime)
total_employee_earnings = float(earned_straight_pay) + float(earned_hourly_overtime) + float(earned_piece_overtime) + float(employee_earnings)
print "This employee earned a total of $%.2f this pay period." % total_employee_earnings
employee_ot_calculation()
straight_hours()
overtime_hours()
travel_time()
employee_piece_earnings()
overtime_piece()

To avoid using global variables, what you want to do is use function arguments and return values.
Function arguments
Let's take your first function as an example.
You can define a variable outside of the scope of your function and pass it as an argument between the two parenthesis. You can then manipulate your variable at your convenience inside of your function. You can pass as many arguments as you want.
number_of_straight_hours_worked = 1 # Define a variable outside of function
def straight_hours(number_of_straight_hours_worked): #Pass as argument
number_of_straight_hours_worked += 1 #Do whatever you want
Returning Values
The function straight_hours takes the input on how many straight hours an employee has worked. Instead of using a global variable, what you want to do is to return the value.
number_of_straight_hours_worked = "" # Define a variable outside of function
def straight_hours(number_of_straight_hours_worked): #Pass as argument
number_of_straight_hours_worked = input("How many hours?")
return number_of_straight_hours_worked
#Then retreive the value by doing
number_of_hours = straight_hours(number_of_straight_hours_worked)
As you can see, the line number_of_hours = straight_hours() calls the functions and affects the return the return value to the number_of_hours variable.
Other notes
I would also advise shrinking and simplifying you variable names.
Also, when you declare a variable like you do at the top of your code, I would advise either declare them as NONE or not do it at all. Declaring them to False which is of type boolean to then convert it to a float makes no sense to me.
Separete your validation code from your actual calculations. This way, you can test your calculations separately.

Related

Trying to create a class which goes in a loop once the class and def is called

I'm creating a simple program to take in time and distance to then state the speed, but I want to do this with classes to learn about oop in python. I'm not figuring out how to set the loop to keep going until the user decides to not go again.
y=True
while y:
class Timer:
def __init__(self,speed):
self.speed=speed
def log(self):
print(mph)
again=input('Go again? y or n: ')
if again=='y':
y=True
else:
print('Thank you')
y=False
m=float(input('Enter the minutes: '))
s=float(input('Enter the seconds: '))
d=float(input('Enter distance: '))
x=(m*60)+s
x_tot=(x/3600)
mph=d/x_tot
t=Timer(mph)
t.log()
You need following code:
y=True
while y:
class Timer:
def __init__(self,speed):
self.speed=speed
def log(self):
print(mph)
global y
again=input('Go again? y or n: ')
if again=='y':
y=True
else:
print('Thank you')
y=False
if y:
m=float(input('Enter the minutes: '))
s=float(input('Enter the seconds: '))
d=float(input('Enter distance: '))
x=(m*60)+s
x_tot=(x/3600)
mph=d/x_tot
t=Timer(mph)
t.log()
else:
break
The y variabel inside log function should be global else it won't change global y referred inside if-else. We need if-else with y so that we can break out of loop if user chooses n. The t=Timer(mph) has to be inside while loop because class is not known outside the loop. Same applies for t.log function call.
Honestly to make your code easier to debug and track where changes are occuring, you should pull the class out of the loop and then reference it inside the loop when you need to use it.
In the init, I would pull out the assignment of the speed variable and just initialize it as none.
def __init__(self):
self.speed = None
Then you can add a separate private setter function to set the speed with user input and do error checking around it. Note, I have set the program to exit with a 0 code if the user inputs something wrong, but you can easily make another loop here that will wait until the user finally does input valid values for all the inputs. The __ double underscore in front of the function name makes it private to the class.
def __set_mph(self):
try:
m = float(input('Enter the minutes: '))
s = float(input('Enter the seconds: '))
d = float(input('Enter distance: '))
x = (m * 60) + s
x_tot = (x / 3600)
self.mph = d / x_tot
except (ValueError, ArithmeticError) as e:
print(f'Invalid user input: {e}')
exit(0)
except Exception as e:
print(f'Unexpected error: {e}')
exit(0)
Now you can update the log function to not even worry about the y variable by changing it to this:
def log(self):
self.__set_mph()
print(mph)
again = input('Go again? y or n: ')
if again == 'y':
return True
else:
print('Thank you')
return False
Now we just initialize the class before the loop and clean it up to be make it more manageable.
t = Timer()
while True:
if not t.log():
break
Final Code:
class Timer:
def __init__(self):
self.speed = None
self.mph = None
def __set_mph(self):
try:
m = float(input('Enter the minutes: '))
s = float(input('Enter the seconds: '))
d = float(input('Enter distance: '))
x = (m * 60) + s
x_tot = (x / 3600)
self.mph = d / x_tot
except (ValueError, ArithmeticError) as e:
print(f'Invalid user input: {e}')
exit(0)
except Exception as e:
print(f'Unexpected error: {e}')
exit(0)
def log(self):
self.__set_mph()
print(self.mph)
again = input('Go again? y or n: ')
if again == 'y':
return True
else:
print('Thank you')
return False
t = Timer()
while True:
if not t.log():
break
OOP is all about modeling your real world objects into programmatic objects that maintain the features and functionality of the real world object to its programatic counterpart's attributes and features, respectively.
Also, those objects should be separated on its own. Creating and calling a class from within a while loop is pretty bad practice. I would encourage you to separate the code based on its purpose. for example, I would have a file called timer.py to handle the Object that matches the timer like so:
# The timer class
class Timer:
def calculate_speed(self, minutes, seconds, distance):
hours = (minutes * 60) + seconds
tot_time = (hours / 3600)
return distance / tot_time
def get_speed(self):
minutes = float(input('Enter the minutes: '))
seconds = float(input('Enter the seconds: '))
distance = float(input('Enter distance: '))
return self.calculate_speed(minutes, seconds, distance)
Then in your main file:
from timer import Timer
timer = Timer()
while True:
user_response = input('Go again? y or n: ').lower()
if user_response == 'n':
break
elif user_response == 'y':
speed = timer.get_speed()
print(f'Your speed is {speed}')
else:
print('Not a valid response')
This makes it easier on the backend too. In other words, if you have an error that relates to the calculations, you know where to start looking.

When user inputs same input twice (expected), how do I combine the input to output?

My test code works for the first record with one day entered but the body of the code does not work. The code continues to run asking for the day and hours worked. I enter "done" and it doesn't accept that either.
I initially thought creating a list for the days entered but wasn't sure when to access the list to print the footer before going to the next input. There are no errors just won't execute as expected. This is an assignment and many of the declarations were already populated.
Expected Results with user input:
Day worked: Tuesday
Hours Worked: 3
Day worked: Tuesday
Hours Worked: 4
Day Total 7
Here's my code.
HEAD1 = "WEEKLY HOURS WORKED"
DAY_FOOTER = "Day Total "
SENTINEL = "done" # Named constant for sentinel value
hoursWorked = 0 # Current record hours
hoursTotal = 0 # Hours total for a day
prevDay = "" # Previous day of week
notDone = True # loop control
days=[]
# Print two blank lines.
print("\n\n")
# Print heading.
print("\t" + HEAD1)
# Print two blank lines.
print("\n\n")
# Read first record
dayOfWeek = input("Enter day of week or done to quit: ")
if dayOfWeek == SENTINEL:
notDone = False
else:
hoursWorked =int(input("Enter hours worked: "))
prevDay = dayOfWeek
hoursTotal = hoursWorked
days.append(dayOfWeek)
print("\t" + DAY_FOOTER + str(hoursTotal))
print(days)
while notDone == True:
dayOfWeek = input("Enter day of week or done to quit: ")
prevDay = dayOfWeek
hoursWorked =int(input("Enter hours worked: "))
hoursTotal = 0
hoursTotal = hoursTotal + hoursWorked
days.append(dayOfWeek)
print(days)
def dayChange(DAY_FOOTER,hoursWorked):
if dayOfWeek == dayOfWeek:
DAY_FOOTER = dayOfWeek
hoursTotal = (hoursWorked + hoursWorked)
print("\t" + DAY_FOOTER + str(hoursTotal))
days.append(dayOfWeek)
else:
print("\t" + DAY_FOOTER + str(hoursTotal))
def endOfProgram(done):
if dayOfWeek == "done":
notDone == False
return```
There are several issues with the code:
First of all, you are not really sensitive to the "done" command within the while loop. You do test the notDone variable, but you never write to this variable while inside the loop. The test should be embedded in the loop itself, and is superfluous outside it. Second of all, with each iteration of the while loop you initialize the hoursTotal variable to 0, so that you do not memorize the values from the previous days. Perhaps you should use an additional list for keeping track of hours, or use a day_of_the_week:hours dictionary.

TypeError: float() argument required to be a string or a number

I'm in Grade 11 Computer Science at my highschool, and I'm just starting out in Python. I'm supposed to make a function called computepay that will ask the user their name, their wage, and their hours that week and automatically calculate the total, including any overtime and not error out when an incorrect input is included. I made different functions for all the inputs, but when I plug it all into my computepay function it tells me this:
TypeError: float() argument must be a string or a number
def mainloop(): #Creating a loop so it doesn't error out.
response = input('Make another calculation?[y/n]') #inputing loop
if response == 'n': #creating input for n
return
if response == 'y':
computepay()
else:
print("\n")
print ("Incorrect input. .")
mainloop()
def getname():
name = input ("What's your name?") #input of name
def getwage():
wage = input ("Hello there! How much money do you make per hour?") #input
try:
float(wage) #Making it so it does not error out when a float
except:
print ("Bad Input")
getwage()
def gethours():
hours = input ("Thanks, how many hours have you worked this week?")
try:
float(hours) #Making it so it does not error out when a float
except:
print("Bad Input")
gethours()
def computepay():
name = getname()
wage = getwage()
hours = gethours()
if float(hours) > float(40):
newhours = float(hours) - float (40) #figuring out the amount of overtime hours the person has worked
newwage = float (wage) * float (1.5) #figuring out overtime pay
overtimepay = float (newwage) * float (newhours) #calculating overtime total
regularpay = (float(40) * float (wage)) + overtimepay #calculating regular and overtime total.
print (name,",you'll have made $",round(regularpay,2),"this week.")
else:
total = float(wage) * float(hours)
print (name,",you'll have made $",round (total,2),"this week.")
mainloop() #creating the loop.
#-------------------------------------------------------------------------------
computepay()
None of these functions are returning anything
name = getname()
wage = getwage()
hours = gethours()
So they all end up being None
Try this
def getname():
return input("What's your name?") # input of name
def getwage():
wage = input("Hello there! How much money do you make per hour?") # input
return float(wage)
def gethours():
hours = input("Thanks, how many hours have you worked this week?")
return float(hours)
What the error message is telling you is that somewhere (on the line number reported in the part of the error message that you didn't show us) you are calling float and giving it an argument (i.e. an input) that is neither a number, nor a string.
Can you track down where this is happening?
Hint: Any Python function which doesn't return anything (with the return keyword) implicitly returns None (which is neither a string nor a number).

making a piggy bank program in python

I'm a beginner to Python and programming, and I'm trying to make a simple piggy bank that will be able to deposit or withdraw pennies, nickels, dimes, and quarters. I don't know how to loop the code or how to store the data if I enter a coin to be able to keep adding to the total number of coins in the bank. I can only do it so it runs and tells me if I add, for example, 100 pennies, that my bank has 100 pennies. but then it resets. How do I do this? my code is probably awful but here's what I have so far based off my current knowledge of python (added empty parts like the "return" and pennies_previous so anyone reading can understand my thought process, and the withdrawstep() function has not been added yet):
print "Welcome to the Piggy Bank!"
def depositstep():
deposit = raw_input("What would you like to deposit? (P for pennies, N for nickels, D for dimes, Q for quarters): ").upper()
if deposit == 'P':
pennies_previous =
pennies_instance = raw_input("How many pennies would you like to deposit?: ")
pennies_total = int(pennies_instance) + pennies_previous
print "There are %s pennies in your bank"% (pennies_total)
return execute()
elif deposit == 'N':
N = raw_input("How many nickels would you like to deposit?: ")
return
elif deposit == 'D':
D = raw_input("How many dimes would you like to deposit?: ")
return
elif deposit == 'Q':
Q = raw_input("How many quarters would you like to deposit?: ")
return
else:
return "Sorry. Please Type P for pennies, N for nickels, D for dimes, or Q for quarters."
def execute():
exc = raw_input("Would you like to deposit or withdraw money? (D for deposit, W for withdraw): ").upper()
if exc == 'D' or exc == 'DEPOSIT':
return depositstep()
elif exc == 'W' or exc == 'WITHDRAW':
return withdrawstep()
else:
return "Sorry. Please type D for deposit or W for withdrawal."
print execute()
You should store your total amount of pennies in the original variable.
pennies_previous= int(pennies_instance) + pennies_previous then the amount of pennies will be stored there.
If you are looking to make the bank continue to store the value of the bank for each session, then you are going to want to save the bank's value to a file. You could do it like this:
1. First, make a file with a name like bankvalue.txt.
2. Then, add these lines before every return:
value = open(bankvalue.txt, 'w') # that opens your bankvalue.txt file in write mode
value.write('\n'pennies_previous) #You should use the answer above for the pennies_previous
value.close() #saves the file
3.Then, in order to tell a person their balance you would use the readline() function
I hope that was what you were looking for
I would use a python dictionary instead of variables:
do so as:
bank = {'pennies':0, 'nickles':1, 'dimes':0, 'quarter':0}
to increase either of those you do
bank['pennies'] += int(pennies_instance) # not need the pennies_previous
Then you need to write that to a file which you could do:
f = open('filename','w')
f.write(bank.items())
f.close
But that don't preserve the python structure. But you can use json module, which is simple as:
import json
f = open('filename','wb')
json.dump(bank,f)
f.close()
And at the start of the script you need to fetch the data from the file, you do this with
f = open('bank.dat','rb')
bank = json.load(f)
It would look like this:
import json
f = open('bank.dat','rb')
bank = json.load(f)
f.close()
## you code goes here.
f = open('bank.dat','wb')
json.dump(bank,f)
f.close()
There are some other problems in your code that should be addressed too.
1) In the 'else' part of your code, if the user inputs the wrong letter it terminates, instead it should call the function again.
2) You don't need to return a string and print it in the 'print execute()', you could just print it in place and don't return anything.

Problems transferring information from one part of a function to another

While working on my program I have run into a problem where the information stored in Menu option 1 is not being transferred to Menu option 2. As you can see it is correctly stored when in menu one. When it returns to go to menu option 2 its like it never went to option 1.
update #1:
some suggestions I've had is to understand scope? from what I can tell the program is not passing the data along to its parent program even though I've typed out return in each of the definitions.
#Must be able to store at least 4 grades
#Each class can have up to 6 tests and 8 hw's
#Weighted 40%*testavg 40% hw average attendance is 20%
#User must be able to input a minimum grade warning
#after each test the your program must calculate the students average and issue warning if necessary
##Define the Modules##
import math
def menu (a): #2nd thing to happen
menuend = 'a'
while menuend not in 'e':
menuend = raw_input("Type anything other then 'e' to continue:\n")
print "What would you like to do ?"
menudo = 0
print "1 - Enter Courses\n2 - Select Course to Edit\n3 - Save File\n4 - Load File\n5 - Exit\n"
menudo = input("Enter Selection:")
if (menudo == 1):
menuchck = 0
menuchck = raw_input("\nYou have entered #1 (y/n)?:\n")
if menuchck in ["Yes","yes","y","Y"]:
x = m1()
else:
print "I'm sorry,",nam,",for the confusion, lets try again\n"
menu()
elif (menudo == 2):
menuchck1 = 0
menuchck1 = raw_input("\nYou have entered #2 (y/n)?:\n")
if menuchck1 in ["Yes","yes","y","Y"]:
x = m2()
else:
print "I'm sorry,",nam,",for the confusion, lets try again\n"
menu()
elif (menudo == 3):
print "Entered 3"
elif (menudo == 4):
print "Entered 4"
else:
print "Anything Else Entered"
def course(): #3rd thing to happen
b = {}
while True:
while True:
print "\n",name,", please enter your courses below ('e' to end):"
coursename = raw_input("Course Name:")
if (coursename == 'e'):
break
will = None
while will not in ('y','n'):
will = raw_input('Ok for this name : %s ? (y/n)' % coursename)
if will=='y':
b[coursename] = {}
print "\n",name,", current course load:\n",b
coursechck = None
while coursechck not in ('y','n'):
coursechck = raw_input("Are your courses correct (y/n)")
if coursechck =='y':
return b
else:
b = {}
print
##Menu Options##
def m1():
a = course()
return a
def m2():
print "Excellent",name,"lets see what courses your enrolled in\n"
print x
return x
###User Input Section###
name = raw_input("Enter Students Name:\n")
a = {}
menu(a)
raw_input("This is the end, my only friend the end")
In your if-elif blocks in the do==1 case, you write m1(), but for the last case, you write x=m1(). You should have the latter everywhere (by typing m1() you only run the function, but do not store the returned x anywhere).
By the way, you can avoid this if-elif confusion using if chck in ["Yes","yes","Y","y"]:

Categories