function not giving back total

Associate
Joined
11 Jul 2009
Posts
1,318
Hello there

New to python, I have a background in java, I'm finding oop in python confusing, this program simply prints out employee info and its suppose calculate their wage, when I run the program it just displays 0, any help appreciated thanks.


Code:
class Pay():
    def __init__(self, name, age, hoursWorked, amount_per_hour, total):
        self.name(name)
        self.age(age)
        self.hoursWorked(hoursWorked)
        self.amount_per_hour = amount_per_hour
        self.total = total

    def name(self):
        return self.__name

    def name(self, newname):
        if not newname:
            raise Exception("NAME FIELD CANNOT BE EMPTY")
        self.__name = newname

    def age(self):
        return self.__age

    def age(self, newvalue):
        if newvalue < 18:
            raise Exception("INVALID AGE")
        self.__age = newvalue

    def hoursWorked(self):
        return self.__hoursWorked

    def hoursWorked(self, newhours):
        if newhours < 0:
            raise Exception("HOURS MUST BE ENTERED")
        self.__hoursWorked = newhours

    def amount_per_hour(self):
        return self.__amount_per_hour

    def amount_per_hour(self, newamount):
        self.__amount_per_hour = newamount

    def total(self):
        return self.__total

    def total(self, newtotal):
        self.__total = newtotal

    def calculate_wage(self):
        self.total = self.hoursWorked * self.amount_per_hour
        return self.total

    def __str__(self):
        return "Name: " + self.__name + "\nAge: " + str(self.__age) + "\nHourWorked: " + str(
            self.__hoursWorked) + "\nAmount per Hour: " + str(self.amount_per_hour) + "\nTotal: " + str(self.total)


p = Pay("Kevin", 34, 40, 9.80, 0)
print(p)

The output

Name: Kevin
Age: 34
HourWorked: 40
Amount per Hour: 9.8
Total: 0

Total field is 0 but I want it to display total wage.
 
Soldato
Joined
3 Jun 2005
Posts
3,067
Location
The South
Never really ventured into Python so just spit-balling but you need to call calculate_wage() after initialising (init) the class (with your data) to actually calculate the wage. Currently you're assigning 0 (zero) to the total variable during init and because no further processing is done to that variable, you're getting 0 as the output.

In theory, you should be able to do something like -
Code:
p = Pay("Kevin", 34, 40, 9.80, 0)
p.calculate_wage()
print(p)


But being honest, i'm not entirely sure why there is a total argument (or the total method/setter with the newtotal variable) for the class init as without calling calculate_wage(), it looks like it just works as a pass-thru :confused:
I suspect it could either be removed entirely or a default value assigned to the function argument, ie -
Code:
class Pay():
    def __init__(self, name, age, hoursWorked, amount_per_hour, total = 0):
...


Hopefully someone with more Python knowledge will come along and either confirm the above or completely annihilate it for being wrong :D
 
Soldato
Joined
21 Jul 2005
Posts
20,049
Location
Officially least sunny location -Ronskistats
I would go with something like:

Code:
class Pay():
    def __init__(self, name, age, hoursWorked, amount_per_hour, Subtotal):
        self.name(name)
        self.age(age)
        self.hoursWorked(hoursWorked)
        self.amount_per_hour = amount_per_hour
        self.Subtotal = hoursWorked * amount_per_hour

..and adjust the code to suit where your calling the functions.

So if your working out a wage, your calling the Subtotal with the function that uses the amount of days they have clocked in for.
 
Associate
OP
Joined
11 Jul 2009
Posts
1,318
Thanks visibleman and Th0nt for taking the time to reply.

I would go with something like:

Code:
class Pay():
    def __init__(self, name, age, hoursWorked, amount_per_hour, Subtotal):
        self.name(name)
        self.age(age)
        self.hoursWorked(hoursWorked)
        self.amount_per_hour = amount_per_hour
        self.Subtotal = hoursWorked * amount_per_hour

..and adjust the code to suit where your calling the functions.

So if your working out a wage, your calling the Subtotal with the function that uses the amount of days they have clocked in for.

This worked thanks

I changed it to

Code:
    def __init__(self, name, age, hours_worked, amount_per_hour, Subtotal):
        self.set_name(name)
        self.age = age
        self.hours_worked = hours_worked
        self.amount_per_hour = amount_per_hour
        self.Subtotal = self.calculate_wage()
 
def calculate_wage(self):
        return self.hours_worked * self.amount_per_hour
 
Soldato
Joined
28 Oct 2006
Posts
12,456
Location
Sufferlandria
Generally, you'd never take an input for a calculated field, so remove total and subtotal from the __init__ function parameters:

Code:
    def __init__(self, name, age, hours_worked, amount_per_hour):
        self.set_name(name)
        self.age = age
        self.hours_worked = hours_worked
        self.amount_per_hour = amount_per_hour
        self.Subtotal = self.calculate_wage()

You're also using the same names for variables and the property names. There's no problems with doing that but it might be making things more difficult to understand if you're new to it:

Code:
    def __init__(self, n, a, hw, aph):
        self.set_name(n)
        self.age = a
        self.hours_worked = hw
        self.amount_per_hour = aph
        self.Subtotal = self.calculate_wage()

I havn't changed the function of the code at all, just renamed the variables to help show the difference between properties of the self object and the variables passed in.
 
Soldato
Joined
3 Jun 2005
Posts
3,067
Location
The South
Generally, you'd never take an input for a calculated field...

Glad i saw this post as i was just about to comment the same and being the Python novice i am, didn't know if it was just a Python 'thing'.

Obviously there's many ways of dealing with classes but out of curiosity with Python, and after nosing a tutorial (https://www.python-course.eu/python3_properties.php), wouldn't you use private variables rather than public and instead use Properties and Methods to set and grab data to end up with something like (haven't tested) the below?

Code:
class Pay:
    def __init__(self, n, a, hw, aph):
        # Private Variables
        self.__name = n
        self.__age = a
        self.__hoursWorked = hw
        self.__amountPerHour = aph
       
    # Name
    @property
    def name(self):
        return self.__name
   
    # Age
    @property
    def age(self):
        return self.__age
       
    # Hours Worked
    @hoursWorked.setter
    def hoursWorked(self, hw):
        self.__hoursWorked = hw
       
    # Amount Per Hour
    @amountPerHour.setter
    def amountPerHour(self, aph):
        self.__amountPerHour = aph

    # Subtotal
    @property
    def subtotal(self):
        return self.__hoursWorked * self.__amountPerHour
       
    # String Output
    def __str__(self):
        return "Name: " + self.__name + "\nAge: " + str(self.__age) + "\nHours Worked: " + str(self.__hoursWorked) + "\nAmount per Hour: " + str(self.__amountPerHour) + "\nTotal: " + str(self.subtotal)
       
# In Use
employee = Pay("Kevin", 34, 40, 9.80)
print(employee) # String Output
print(employee.name) # Name = Kevin
print(employee.age) # Age = 34
print(employee.subtotal) # Subtotal = 392

# Recalculate Using Different Figures
employee.hoursWorked = 36
employee.amountPerHour = 10.50
print(employee.subtotal) # Subtotal = 378
 
Associate
OP
Joined
11 Jul 2009
Posts
1,318
Can anyone tell my total and average aren't being printed out or even calculating by the looks of it

Code:
list = []
total = 0
num = 0

keep_going = True


def get_input():
    while keep_going:
        try:
            num = int(input("Please enter numbers into list or 0 to exit: "))
            if num == 0:
                break
            list.append(num)
        except ValueError:
            print("VALUE MUST BE INTEGER! ")
    sum_array(num)
    calculate_average(num)
    print_answers(num, average)


def sum_array(num):
    for nums in list:
        num += int(nums)


def calculate_average(num):
    global average
    average = num / len(list)


def print_answers(num, average):
    print(list)
    print("Total: ", num)
    print("Average: ", average)


get_input()
 
Associate
Joined
29 Jan 2008
Posts
994
I don't use python at all but you need to be doing something more like this:

Code:
list = []
keep_going = True


def get_input():
    while keep_going:
        try:
            num = int(input("Please enter numbers into list or 0 to exit: "))
            if num == 0:
                break
            list.append(num)
        except ValueError:
            print("VALUE MUST BE INTEGER! ")
    total = sum_array()
    average = calculate_average(total)
    print_answers(total, average)


def sum_array():
    total = 0

    for item in list:
        total += int(item)

    return total


def calculate_average(total):
    return total / len(list)


def print_answers(total, average):
    print(list)
    print("Total: ", total)
    print("Average: ", average)


get_input()

As to why your solution doesn't work, well there are a few problems. The main one is due to how value types, reference types and object references work in python. I know just enough about that to know that I can't describe it properly to you so I suggest you do some googling. Start here maybe: https://www.geeksforgeeks.org/pass-by-reference-vs-value-in-python/ https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/. You might want to read up on variable scopes as well.
 
Back
Top Bottom