Reputation: 69
I am having some trouble passing a variable into a function and having it return a desired value. For clarity, I am obtaining a record from a PostgreSQL table as a tuple and then passing the relevant index of that tuple into a class variable. Everything else seems to work but this and I have no idea why.
The code is as follows:
from datetime import date
from decimal import Decimal
from config import config
import psycopg2
conn = None
try:
params = config()
conn = psycopg2.connect(**params)
cur = conn.cursor()
cur.execute('SELECT * FROM testdb.vitals ORDER BY "vitalsID"')
except (Exception, psycopg2.DatabaseError) as error:
print(error)
row = cur.fetchone()
class Vitals:
birth = date(1990, 12, 12)
today = date.today()
years = today.year - birth.year
age = today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
weight = row[2]
height = row[3]
activity = row[4]
goal = row[5]
fatRatio = row[6]
carbohydrateRatio = row[7]
proteinRatio = row[8]
def __init__(self):
# connect and initialise vitals
pass
# display on gui
@classmethod
def activityText(cls):
if cls.activity == Decimal(1.20):
return testActivity * 2
@classmethod
def bmr(cls):
return (Decimal(10) * cls.weight) + (Decimal(6.25) * cls.height) - (Decimal(5) * cls.age) + Decimal(5)
@classmethod
def tdee(cls):
return Decimal(outputBmr * cls.activity)
@classmethod
def net(cls):
if cls.goal == 1:
return outputTdee - (outputTdee * Decimal(0.1))
else:
return outputTdee
importVitals = Vitals
testActivity = importVitals.activity
print(testActivity)
testActivityfunc = importVitals.activityText()
print(testActivityfunc)
outputBmr = round(importVitals.bmr())
print(outputBmr)
outputTdee = round(importVitals.tdee())
print(round(outputTdee))
outputNet = round(importVitals.net())
print(outputNet)
if importVitals.activity == Decimal(1.20):
print('Hello')
else:
print("\n")
print(importVitals.activity)
print(type(importVitals.activity))
The key class method is here:
@classmethod
def activityText(cls):
if cls.activity == Decimal(1.20):
return testActivity * 2
Output (following alteration of the final if statement in the module) is as follows:
1.20
<class 'decimal.Decimal'>
None
1751
2101
1891
1.20
<class 'decimal.Decimal'>
Process finished with exit code 0
For readability, here are the print statements:
testActivity = importVitals.activity
print(testActivity)
print(type(importVitals.activity))
testActivityfunc = importVitals.activityText()
print(testActivityfunc)
outputBmr = round(importVitals.bmr())
print(outputBmr)
outputTdee = round(importVitals.tdee())
print(round(outputTdee))
outputNet = round(importVitals.net())
print(outputNet)
if importVitals.activity == Decimal(1.20):
print('Hello')
else:
print("\n")
print(importVitals.activity)
print(type(importVitals.activity))
The class method in question always returns None
. Also note the if statement at the end of the module. It always runs the else branch which, at least to me, bizarrely prints 1.20
and <class 'decimal.Decimal'>
. So if Python recognises the instanced class variable of importVitals.activity
as having the value 1.20
and the variable type of <class 'decimal.Decimal'>
, then why is the if statement or the class method not returning what I would like it to? Is there something I am doing wrong here?
Just to reiterate, all of the other methods and print statements are working as expected so I am quite puzzled by this.
Thank you to anybody who took the time to read this. I would appreciate any help you can offer.
Upvotes: 1
Views: 288
Reputation: 1644
Here is a more object oriented way to implement the above code:
import sys
import psycopg2
from datetime import date
from decimal import Decimal
from config import config
class Vitals:
def __init__(self, row):
self.birth = date(1990, 12, 12)
self.today = date.today()
self.years = today.year - birth.year
self.age = today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
self.weight = row[2]
self.height = row[3]
self.activity = Decimal(float(row[4]))
self.goal = row[5]
self.fatRatio = row[6]
self.carbohydrateRatio = row[7]
self.proteinRatio = row[8]
def activityText(self):
if self.activity == Decimal(1.20):
return self.activity * 2
def bmr(self):
return (Decimal(10) * self.weight) +
(Decimal(6.25) * self.height) -
(Decimal(5) * self.age) +
Decimal(5)
def tdee(self):
return Decimal(self.bmr() * self.activity)
def net(self):
if self.goal == 1:
return self.tdee() - (self.tdee() * Decimal(0.1))
else:
return self.tdee()
def getDataFromDatabase(sql):
conn = None
try:
params = config()
conn = psycopg2.connect(**params)
cur = conn.cursor()
cur.execute(sql)
except (Exception, psycopg2.DatabaseError) as error:
print(error)
return None
return cur.fetchone()
def main():
sql = 'SELECT * FROM testdb.vitals ORDER BY "vitalsID"'
row = getDataFromDatabase(sql)
vitals = Vitals(row)
#Here you can do your stuff with vitals
main()
You can create more objects, and fill them with different values. I suggest cast the values of row
in the constructor to proper types, like activity
to Decimal.
I cannot guarantee this version would solve your initial problem, I tried another solution, but since the question has a proper answer, that wasn't my main goal.
I saw the post that you said a one calorie difference is acceptable, so I suggest creating a function, that has a treshold of one calorie, and if the abs
of the difference between 2 objects is less than the treshold, return true.
Upvotes: 1
Reputation: 1395
Looks like you have numeric errors:
>>> Decimal(1.20)
Decimal('1.1999999999999999555910790149937383830547332763671875')
>>> Decimal("1.20")
Decimal('1.20')
Use strings as an input for your decimals and everything should be fine. Floats are good for fast computations, but they are not a good fit for accuracy.
Upvotes: 1