__init__ within class supposedly missing arguments? - python

class FoodItem:
def __init__(self, item_name, amount_fat, amount_carbs, amount_protein, num_servings):
self.item_name = "None"
self.amount_fat = 0.0
self.amount_carbs = 0.0
self.amount_protein = 0.0
self.num_servings = 0.0
def get_calories(self, num_servings):
# Calorie formula
calories = ((self.fat * 9) + (self.carbs * 4) + (self.protein * 4)) * num_servings;
return calories
def print_info(self):
print('Nutritional information per serving of {}:'.format(self.name))
print(' Fat: {:.2f} g'.format(self.fat))
print(' Carbohydrates: {:.2f} g'.format(self.carbs))
print(' Protein: {:.2f} g'.format(self.protein))
if __name__ == "__main__":
food_item1 = FoodItem()
item_name = input()
amount_fat = float(input())
amount_carbs = float(input())
amount_protein = float(input())
food_item2 = FoodItem(item_name, amount_fat, amount_carbs, amount_protein)
num_servings = float(input())
food_item1.print_info()
print('Number of calories for {:.2f} serving(s): {:.2f}'.format(num_servings,
food_item1.get_calories(num_servings)))
print()
food_item2.print_info()
print('Number of calories for {:.2f} serving(s): {:.2f}'.format(num_servings,
food_item2.get_calories(num_servings)))
Results in the error:
Traceback (most recent call last):
File "main.py", line 22, in <module>
food_item1 = FoodItem()
TypeError: __init__() missing 5 required positional arguments: 'item_name', 'amount_fat', 'amount_carbs', 'amount_protein', and 'num_servings'
I'm not spotting an obvious error, but I'm new to initializing classes. The error seems to say that I'm missing arguments within the original init, but considering they were initialized to 0/'none' values, I don't understand that.
Perhaps someone can catch the error?

You have to initialize your class with ALL the arguments: item_name, amount_fat, amount_carbs, amount_protein and num_servings.
# here, you have to provide the arguments
food_item1 = FoodItem()
...
# and here, you are missing the 'num_servings' argument
food_item2 = FoodItem(item_name, amount_fat, amount_carbs, amount_protein)
Just in case, you can provide default values to an argument like so:
# here, the argument will default to '0' if you do not provide a value.
class Example:
def __init__(self, argument=0):
self.argument = argument
example = Example()
print(example.argument)
>>> 0

Your code is not saying what to match for example self.amount_fat with which argument you are talking about.
You should write:
self.amount_fat = amount_fat
And then announce was self.amount_fat is, otherwise your program will not know where to read.
def __init__(self, item_name, amount_fat, amount_carbs, amount_protein, num_servings):
self.item_name = item_name
self.amount_fat = amount_fat
self.amount_carbs = amount_carbs
self.amount_protein = amount_protein
self.num_servings = num_servings
You can then add what you coded initially.

Related

decorating method using instance method

I am trying to decorate my instance car_details with another instance method decor but am not able to figure out why this is giving the error. while i call the call car_details method like below
if __name__ == '__main__':
car_type = input("Enter type of car: ")
price = int(input("Enter price of car: "))
obj = Car(car_type, price)
decor = obj.decor
details = obj.car_details
tax = {1: "Yes", 2: "No"}
to_apply = int(input("Select 1 for applying tax and 0 for No:"))
ans = tax.get(to_apply)
res = decor(details)
res(ans)
then it works properly, but while i try it with the #decorator at that time i get issue.
TypeError: decor() missing 1 required positional argument: 'func'
TYPE = {'hybrid': 'Hybrid', 'petrol': 'Petrol', 'deasel': 'Deasel'}
def tax_price(car_type):
if car_type == 'hybrid':
SGST = 300000
GST = 500000
elif car_type == 'petrol':
SGST = 200000
GST = 400000
elif car_type == 'deasel':
SGST = 100000
GST = 300000
return SGST+GST
class Car:
def __init__(self, car_type, price):
self.car_type = car_type
self.price = price
def decor(self, func):
def wrapper(apply_tax):
if apply_tax == 'Yes':
car_tax = tax_price(self.car_type)
self.price += car_tax
func()
else:
func()
return wrapper
#decor
def car_details(self):
print("Car Type:", self.car_type)
print("Car Price: ", self.price)
if __name__ == '__main__':
car_type = input("Enter type of car: ")
price = int(input("Enter price of car: "))
obj = Car(car_type, price)
tax = {1: "Yes", 2: "No"}
to_apply = int(input("Select 1 for applying tax and 0 for No:"))
ans = tax.get(to_apply)
wrp = obj.car_details()
wrp(ans)
I see a few problems here. The biggest problem is you seem to be trying to use a decorator when a decorator is really (and I mean really) not suitable for this situation. If this code is not experimental and is to be maintained by someone, I strong suggest simplifying to:
def car_details(self, apply_tax):
if apply_tax == 'Yes':
car_tax = tax_price(self.car_type)
self.price += car_tax
print("Car Type:", self.car_type)
print("Car Price: ", self.price)
But if you are just experimenting and want to make it work with decorators, I see the following problems:
When a decorator is called, the only arg passed to it is the function being decorated, not self which is not passed in at all. That means def decor(self, func): will need to change to def decor(func):.
When the decorated function, which is a method of a class, is invoked, the first arg will be self. That means def wrapper(apply_tax): will need to change to def wrapper(self, apply_tax):.
When the wrapped functions is invoked, it needs self as its only arg. That means func() will need to change to func(self) (in both places).
So, that gives:
def decor(func):
def wrapper(self, apply_tax):
if apply_tax == 'Yes':
car_tax = tax_price(self.car_type)
self.price += car_tax
func(self)
else:
func(self)
return wrapper
But, how does the decorated function get a value for apply_tax? It needs to be passed as an arg. So, you'll need ...
wrp = obj.car_details(ans)
Since this is a call on an instance, Python will automatically add self as the first arg and since car_details is decorated it will effectively be calling wrapper(self, ans).

getting a typeerror when trying to sum arguments using a function

So i am working on a budget calculator and i run into an error where i cant add the the expenses
Heres the error:
Traceback (most recent call last):
File "/home/jason/Documents/budgetcalc/./budgetcalc.py", line 50, in <module>
totexpenses = exp.expenses(args.expenses)
TypeError: 'int' object is not callable
code used for the calculation:
class Expenses(Budgeter):
def __init__(self):
super().__init__()
def expenses(self, expense_list):
self.expenses = expense_list
total = sum(self.expenses)
return total
# instance
exp = Expenses()
defined argument:
parser.add_argument('--expenses', help='n amounts of expenses', nargs='*', type=int)
and heres the code for that argument:
if args.expenses:
totexpenses = exp.expenses(args.expenses)
# print(f'${income} net income')
print(f'${totexpenses} in expenses')
heres the full code if needed:
#!/usr/bin/env python
import argparse
import sys
class Budgeter:
def __init__(self):
self.wage = 0
self.netincome = 0
self.expenses = 0
self.hours = 0
class Income(Budgeter):
def __init__(self):
super().__init__()
def income(self, wage, hours):
self.wage = wage
self.hours = hours
self.netincome = (float(self.wage) * int(self.hours)) * 4.34
return self.netincome
class Expenses(Budgeter):
def __init__(self):
super().__init__()
def expenses(self, expense_list):
self.expenses = expense_list
total = sum(self.expenses)
return total
parser = argparse.ArgumentParser()
parser.add_argument('--wage', help='enter a wage ($$/hr)')
parser.add_argument('--hours', help='hours per week')
parser.add_argument('--expenses', help='n amounts of expenses', nargs='*', type=int)
parser.add_argument('--interactive', help='get a prompt for easy use', action='store_true')
args = parser.parse_args()
pc_budgeter = Budgeter()
rawinc = Income()
exp = Expenses()
if args.wage and args.hours:
if int(args.hours) <= 24:
income = rawinc.income(args.wage, args.hours)
if args.expenses:
totexpenses = exp.expenses(args.expenses)
print(f'${income} net income')
print(f'${totexpenses} expenses')
else:
print('missing --expenses')
else:
print(f'there are only 24 hours in a day not {args.hours}')
else:
parser.print_help()
The Budgeter class defines an integer attribute named expenses:
class Budgeter:
def __init__(self):
self.wage = 0
self.netincome = 0
self.expenses = 0
... and then the Expenses class, inheriting from Budgeter, defines a method also named expenses:
class Expenses(Budgeter):
def __init__(self):
super().__init__()
def expenses(self, expense_list):
Rename one of those things to a different name.
By the way, you don't need __init__ in the child class, because the only thing it does is call the parent __init__, which is the default behavior anyway.

Passed parameters/variables aren't correct

While practicing OOP with inheritance in my second class I have problems adding my parameters, as you can see I have: (self, name, tred, PM, PM2, ra, ra2). But when run the program it tells me that I can not multiply Nonetype, I print them to see what's wrong and i get that some of the parameters are incorrect.
The first class works fine (Atomic_d), I just need to understand how does it work the variables in the second class: Molecular_d
How can I fix this?
This is the complete code picture
import math
class Atomic_d():
def __init__(self,name="",red="",PM=None,ra=None):
self.name = name
self.red = red
self.PM = PM
self.ra = ra
def density(self):
redes = {"BCC":2,"FCC":4,"HCP":6}
self.red = self.red.upper()
nred = redes.get(self.red)
nav = round(6.022*(10**23),3)
if nred == 2:
a = (4*(self.ra))/((3)**0.5)
elif nred == 4:
a = (4*(self.ra))/((2)**0.5)
else:
per = round(12 * self.ra,3)
hipoc = round((2*self.ra)**2,3)
basec = round(self.ra**2,3)
apo = round(math.sqrt(hipoc - basec),3)
a = round((per * apo / 2),3)
if nred == 2 or nred == 4:
vol = a**3
elif nred == 6:
vol = round(a * 3.266 * self.ra,3)
density = round((((nred*self.PM)/(nav*vol))*10**21),3)
return "{} : {} g/cc".format(self.name,density)
class Molecular_d(Atomic_d):
def __init__(self,name="",tred="",PM=None,ra=None,PM2=None,ra2=None):
super().__init__(name,PM,ra)
self.PM2 = PM2
self.ra2 = ra2
self.tred = tred
def density(self):
tredes = {"NACL":8}
self.tred = self.tred.upper()
nred = tredes.get(self.tred)
nav = round(6.022*(10**23),3)
if nred == 8:
l = round(((2*self.ra)*(2*self.ra2)),3)
vol = l**3
density = ((8*(self.PM + self.PM2))/(nav*vol))
return "{}: {} g/cc".format(self.name,density)
This is the error that happens when I try to debug
I print every variable to see what is the problem
print("Hi I'm name",self.name)
print("Hi I'm ra",self.ra)
print("Hi I'm ra2",self.ra2)
print("Hi I'm PM",self.PM)
print("Hi I'm PM2",self.PM2)
Hi I'm name Ox de magnesio
Hi I'm ra None
Hi I'm ra2 0.14
Hi I'm PM 16.0
Hi I'm PM2 0.072
Traceback:
TypeError Traceback (most recent call last)
<ipython-input-21-bb7a69690a34> in <module>
1 magnesium_ox = Molecular_d("Ox de magnesio","NaCl",24.31,16.0,0.072,0.14)
2
----> 3 magnesium_ox.density()
<ipython-input-19-064f60b8cfce> in density(self)
52
53 if nred == 8:
---> 54 l = round(((2*self.ra)*(2*self.ra2)),3)
55 vol = l**3
56
TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
When you make the call to super()_init(), you leave out the red argument. Python assumes that the three arguments you are passing are name, red, and pa, even though that's seems not to be what you intended.
When you don't attach parameter= to an argument, Python assumes you are giving them from left to right. You need to write:
super().__init__(name=name, PM=PM, ra=ra)
You need to be using keyword arguments if you are not going to put them same order as the class. Try changing the Molecular_d to this below:
class Molecular_d(Atomic_d):
def __init__(self,name="",tred="",PM=None,ra=None,PM2=None,ra2=None):
super().__init__(name=name,PM=PM,ra=ra)
self.PM2 = PM2
self.ra2 = ra2
self.tred = tred
def density(self):
tredes = {"NACL":8}
self.tred = self.tred.upper()
nred = tredes.get(self.tred)
nav = round(6.022*(10**23),3)
if nred == 8:
l = round(((2*self.ra)*(2*self.ra2)),3)
vol = l**3
else:
vol = 10
density = ((8*(self.PM + self.PM2))/(nav*vol))
return "{}: {} g/cc".format(self.name,density)
mag = Molecular_d(name="a", tred="as", PM=1.1, ra=0.2, PM2=2.3, ra2=40.1)
result = mag.density()
print(result)
<< 'a: 4.5167718365991366e-24 g/cc'
I added in a default value of vol, because i'm not sure
You have that:
class Atomic_d():
def __init__(self,name="",red="",PM=None,ra=None):
But, initialization is:
class Molecular_d(Atomic_d):
def __init__(self,name="",tred="",PM=None,ra=None,PM2=None,ra2=None):
super().__init__(name,PM,ra)
it:
super().__init__(name,PM,ra)
goes to:
def __init__(self,name="",red="",PM=None,ra=None):
as
__init__(self,name=name,red=PM,PM=ra,ra=None):
So, ra param was not initialised.

Having errors in inheritance in Python

I am trying to create a program with a real estate agent in mind. In this program, I am trying to cover the aspects of a home to rent with all the basic parameters in mind. However I am having some errors.
class Apartment:
def __init__(self, aptNumber, address, bedrooms, baths):
self._aptNumber = aptNumber
self._address = address
self._bedrooms = int(bedrooms)
self._baths = float(baths)
def _securiyDep(self):
securityDeposit = 330(bedrooms)
def _rent(self):
rent = 250(bedrooms) + 150(bathrooms)+200
def _renter(self):
renter = "vacant"
def setSecDep(self, deposit):
self._deposit = 1000
def setRent(self, rentMoney):
self._rentMoney = 800
def setRenter(self, renter):
self._renter = "Vacant"
def getData(self, Data):
self._Data = Data
def isVacant(self, vacancy):
self._vacancy = "True" or "False"
def __repr__(self):
s = self._aptNumber+ " located at " + str(self._address) + " is rented at" + self._rent
s+= " and has a security deposit = " + self._deposit + " and is = " + self._vacancy
return s
# Test code for the Apartment Class
if __name__ == "__main__":
apts = []
apts.append(Apartment("10C", "107 E. Main", 3, 1.5))
apts.append(Apartment("14B", "109 E. Main", 4, 2))
apts.append(Apartment("13", "2207 W. Broadway", "5", "2.5"))
for apt in apts:
print(apt)
print()
apts[0].setRent("1245")
apts[0].setRenter("Rocky Quartzite")
apts[1].setSecDep("1000")
apts[1].setRenter("Millie Milton")
print(apts[0].getData())
print()
for apt in apts:
if not apt.isVacant():
print(apt)
print()
apts[0].setRenter("")
print(apts[0])
I am having the error
print(apts[0].getData())
<__main__.Apartment object at 0x0000000003124208>
TypeError: getData() missing 1 required positional argument: 'Data'
<__main__.Apartment object at 0x0000000003124240>
Can someone please help with the errors?
You call getData with no arguments on line 60: print(apts[0].getData()). In your definition it takes a parameter called Data.
You define getData to take two arguments, namely self which is a refernce to the instance you are operating on, and which is "automatically" supplied, and the second argument is Data
def getData(self, Data):
self._Data = Data
But when you call getData you don't supply the second argument Data
apts[0].getData()
Thus the interpreter tells you that 1 required argument is missing, which in your case is Data.
Since getData in your case actually sets the Data variable, it would be better to call it setData
If you want to retrive the Data variable the getter would have to looke something like this
def getData(self):
return self._Data

Parent and child classes unexpected keyword argument

I was experimenting with parent and child classes in python. I got an error that I can't seem to solve, both the error and code are posted below. If you could post a reason why this is happening and an edit of my code how to fix this it would be much appreciated.
# Classes Example
class vehicle():
def __init__(self,name,weight,wheels,color):
self.name = name
self.weight = weight
self.wheels = wheels
self.color = color
def __str__(self):
return("Hi, iam a vehicle called " + self.name)
def wow(self):
return(self.weight/self.wheels)
class car(vehicle):
def __init__(self,doors,quantity,mpg):
self.doors = doors
self.quantity = quantity
self.mpg = mpg
def distance(self):
return(self.quantity/self.mpg)
# Main Program
object1 = vehicle("Audi A3",1000,4,"blue")
print(object1)
print(object1.name)
object1.name = "Audi S3"
print(object1.name)
print(object1.weight)
object2 = vehicle(name = "Claud Butler" , color = "Red" , wheels = 2, weight = 20)
print(object2)
print(object2.wow())
object3 = car(name = "Burty", color = "Pink" , wheels = 3, weight = 500, doors = 3 , quantity = 10, mpg = 1000)
print(object3.color)
print(object3.wow())
print(object3.distance())
I get the following error:
Traceback (most recent call last):
File "H:\my documents\Computing\Class example.py", line 39, in <module>
object3 = car(name = "Burty", color = "Pink" , wheels = 3, weight = 500, doors = 3 , quantity = 10, mpg = 1000)
TypeError: __init__() got an unexpected keyword argument 'name'
The error is raised in the following line:
object3 = car(name = "Burty", color = "Pink" , wheels = 3, weight = 500, doors = 3 , quantity = 10, mpg = 1000)
There, you are calling the car constructor with (amongst others) a name parameter. Now, if you look at the define constructor of the car type, you see the following:
class car(vehicle):
def __init__(self,doors,quantity,mpg):
self.doors = doors
self.quantity = quantity
self.mpg = mpg
As you can see, there is no name parameter in the parameter list.
I assume that you expected the car child class to inherit all the constructor parameters from the parent vehicle class but that’s not actually the case. Unless you explicitely duplicate those parameters, they won’t be there. You also have to call the parent’s constructor explicitely. All in all, your car constructor should look like this:
def __init__(self, name, weight, wheels, color, doors, quantity, mpg):
# call the base type’s constructor (Python 3 syntax!)
super().__init__(name, weight, weels, color)
self.doors = doors
self.quantity = quantity
self.mpg = mpg
The method
__init__(self,doors,quantity,mpg):
does not have an argument called name. If you want it, you should add it.

Categories