TypeError: Not supported between instances of 'function' and 'int' - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: TypeError: Not supported between instances of 'function' and 'int' (/thread-22701.html) |
TypeError: Not supported between instances of 'function' and 'int' - palladium - Nov-23-2019 Hi all, I am new to programming and am trying (learning) to build a calculator to calculate the risk of heart diseases based on a few variables. Part of the calculation requires recognition of certain high risk criteria and this is where I am at the moment. The code is split into two files, variables.py (the variables module) and framingham.py: Variables.py: def age(): a = eval(input("Please enter age in years: ")) if a < 35: return 35 else: return a def systolic_blood_pressure(): b = eval(input("Please enter SBP: ")) if b < 75: return 75 else: return b def cholesterol_ratio(total_cholesterol, HDL_cholesterol): ratio = total_cholesterol/HDL_cholesterol return ratio def smoker(): a = eval(input("Are you a smoker? 0 = no, 1 = yes " )) return a def diabetes(): a = eval(input("Are you a diabetic? 0 = no 1 = yes " )) return a def LVH(): a = eval(input("Does the ECG show LVH? 0 = no 1 = yes " )) return a total_cholesterol = eval(input("Please enter total cholesterol. ")) HDL_cholesterol = eval(input("Please enter HDL cholesterol. "))framingham.py (incomplete): import variables from sys import exit #define and return if high risk criteria present class highrisk(object): def __init__(self, age, diabetes, systolic_blood_pressure, total_cholesterol): self.age = variables.age self.diabetes = variables.diabetes self.systolic_blood_pressure = variables.systolic_blood_pressure self.total_cholesterol = variables.total_cholesterol if total_cholesterol >= 7.5: print("You are at high risk of developing heart disease. ") elif systolic_blood_pressure >= 180: print("You are at high risk of developing heart disease. ") elif age >= 60 and diabetes == 1: print("You are at high risk of developing heart disease. ") else: pass #no output needed if none of the criteria are met #actual risk calculator class risk_calculator_male(): pass class risk_calculator_female(): pass highrisk(variables.age, variables.diabetes, variables.systolic_blood_pressure, variables.total_cholesterol)(The pass in the last 2 classes are temporary as I haven't finished researching/planning the formula yet) When I run framingham.py in the CLI, I get the following traceback: I thought the eval() function already converts the string to int/float?Some help would be much appreciated. Thanks RE: TypeError: Not supported between instances of 'function' and 'int' - Gribouillis - Nov-23-2019 systolic_blood_pressure is a function. It must be called with parentheses () elif systolic_blood_pressure() >= 180:Apart from that, pythonistas usually avoid eval() for security reasons. In your case, you could use ast.literal_eval() instead of eval() . Import ast first. Also as you're entering numbers, you could simply use int() or float() , which is better than evalb = float(input("Please enter SBP: ")) RE: TypeError: Not supported between instances of 'function' and 'int' - palladium - Nov-23-2019 Thanks so much for your help! RE: TypeError: Not supported between instances of 'function' and 'int' - palladium - Nov-25-2019 So now I have finished the code, but still need some help tidying things up a little. import variables import math class common(object): # common bits for both genders def a(): a = 11.1122-0.9119*(math.log(variables.systolic_blood_pressure))-0.2767*(variables.smoking)-0.7181*(math.log(variables.cholesterol_ratio(variables.total_cholesterol,variables.HDL_cholesterol)))-0.5865*(variables.LVH) return a def mu1(): mu1 = 4.4181+m return mu1 #calculates risks for male def risk_calculator_male(): age = variables.age diabetes = variables.diabetes a = common.a() mu1 = common.mu1() m = a-1.4792*(math.log(age))-0.1759*(diabetes) #mu1 = 4.4181 + m #commented out to demonstrate error sigma = math.exp(-0.3155-0.2784*m) mu2 = (math.log(5)-mu1)/sigma p = 1-math.exp(-math.exp(mu2)) #p is the five year risk i.e. the intended output of the function return round(p*100,2) def risk_calculator_female(): age = variables.age diabetes = variables.diabetes a = common.a() mu1 = common.mu1() m = a-5.8549+1.8515*((math.log(age/74))**2)-0.3758*(diabetes) #mu1 = 4.4181+m sigma = math.exp(-0.3155-0.2784*m) mu2 = (math.log(5)-mu1)/sigma p = 1-math.exp(-math.exp(mu2)) return round(p*100,2) def genderassignment(): #prompts user to enter gender and assigns correct calculator gender = input("Please enter gender, m for male and f for female. ") if gender == 'm': print(f"Your five year risk is: {risk_calculator_male()}% .") elif gender == 'f': print(f"Your five year risk is: {risk_calculator_female()}%. ") else: print("Does not compute!") return genderassignment() genderassignment()As you can see from the code above there are many common elements between the functions risk_calculator_male and risk_calculator_female, being a, mu1, sigma and mu2 (in fact everything is common except m). I want to try and put all the common bits in the common class but when I do it like above, I get an error message saying m is not defined in class common: I can't make m global as it is different in both functions ( and I've read its bad practice anyway) and I can't define m in the common module because it depends on what gender the user enters. Is there a way around this, or do I just need to type it out in each function, like this:import variables import math class common(object): # common bits for both genders def a(): a = 11.1122-0.9119*(math.log(variables.systolic_blood_pressure))-0.2767*(variables.smoking)-0.7181*(math.log(variables.cholesterol_ratio(variables.total_cholesterol,variables.HDL_cholesterol)))-0.5865*(variables.LVH) return a #calculates risks for male def risk_calculator_male(): age = variables.age diabetes = variables.diabetes a = common.a() mu1 = common.mu1() m = a-1.4792*(math.log(age))-0.1759*(diabetes) mu1 = 4.4181 + m sigma = math.exp(-0.3155-0.2784*m) mu2 = (math.log(5)-mu1)/sigma p = 1-math.exp(-math.exp(mu2)) return round(p*100,2) def risk_calculator_female(): age = variables.age diabetes = variables.diabetes a = common.a() mu1 = common.mu1() m = a-5.8549+1.8515*((math.log(age/74))**2)-0.3758*(diabetes) mu1 = 4.4181+m sigma = math.exp(-0.3155-0.2784*m) mu2 = (math.log(5)-mu1)/sigma p = 1-math.exp(-math.exp(mu2)) return round(p*100,2) def genderassignment(): #prompts user to enter gender and assigns correct calculator gender = input("Please enter gender, m for male and f for female. ") if gender == 'm': print(f"Your five year risk is: {risk_calculator_male()}% .") elif gender == 'f': print(f"Your five year risk is: {risk_calculator_female()}%. ") else: print("Does not compute!") return genderassignment() genderassignment()Thanks again. RE: TypeError: Not supported between instances of 'function' and 'int' - Gribouillis - Nov-25-2019 I think you can refactor this to avoid repetitions import variables import math class Calculator(object): # common bits for both genders age = variables.age diabetes = variables.diabetes @property def a(self): a = 11.1122-0.9119*(math.log(variables.systolic_blood_pressure))-0.2767*(variables.smoking)-0.7181*(math.log(variables.cholesterol_ratio(variables.total_cholesterol,variables.HDL_cholesterol)))-0.5865*(variables.LVH) return a @property def mu1(self): mu1 = 4.4181 + self.m return mu1 def risk(self): sigma = math.exp(-0.3155-0.2784 * self.m) mu2 = (math.log(5) - self.mu1)/sigma p = 1-math.exp(-math.exp(mu2)) #p is the five year risk i.e. the intended output of the function return round(p*100,2) class MaleCalculator(Calculator): @property def m(self): return self.a-1.4792*(math.log(self.age))-0.1759*(self.diabetes) class FemaleCalculator(Calculator): @property def m(self): return self.a-5.8549+1.8515*( (math.log(self.age/74))**2)-0.3758*(self.diabetes) #calculates risks for male def risk_calculator_male(): return MaleCalculator().risk() def risk_calculator_female(): return FemaleCalculator().risk() def genderassignment(): #prompts user to enter gender and assigns correct calculator gender = input("Please enter gender, m for male and f for female. ") if gender == 'm': print(f"Your five year risk is: {risk_calculator_male()}% .") elif gender == 'f': print(f"Your five year risk is: {risk_calculator_female()}%. ") else: print("Does not compute!") return genderassignment() genderassignment() RE: TypeError: Not supported between instances of 'function' and 'int' - palladium - Dec-02-2019 Thanks. I don't quite fully understand decorators and the property method yet, but I assume the @property decorator in this case is used to "glue" all the common bits together for the risk function? RE: TypeError: Not supported between instances of 'function' and 'int' - Gribouillis - Dec-02-2019 The following example illustrates the basic effect of the @property decorator >>> >>> class Foo: ... def spam(self): ... return 100 ... >>> class Bar: ... @property ... def spam(self): ... return 100 ... >>> foo = Foo() >>> foo.spam <bound method Foo.spam of <__main__.Foo object at 0x7f7d3997b550>> >>> foo.spam() 100 >>> bar = Bar() >>> bar.spam 100 >>>Do you see the difference between classes Foo and Bar? RE: TypeError: Not supported between instances of 'function' and 'int' - palladium - Dec-04-2019 From what I understand after doing some reading (I'm still new to this!): class Foo makes spam a method which returns 100 when called, whilst class Bar uses the property getter method to get the value of attribute spam (which is 100). In other words, class Bar can be rewritten as: class Bar: def __init__(self,spam=100): self.spam = spam def get_spam(self): return self.spam >>>bar = Bar() >>>bar.spam 100line 12 in your snippet returns some funny stuff because the spam attribute of foo doesn't really exist, whereas line 14 works because the method spam() is defined in lines 3-4. Am I missing something out..? (sorry this is the best I could explain/putit in words)... RE: TypeError: Not supported between instances of 'function' and 'int' - stullis - Dec-04-2019 The trick in Griboulis's code is the @property decorator. Decorators wrap the function immediately following it in another function to add some behavior to it. @property in particular creates an attribute with the name of the following function. The benefit of using @property is that it enables setter and getter methods all using the name of the attribute, "spam" in this case. Setters and getters can be used to run additional code when the attribute changes. This is useful for attributes that need to be managed so that the object is correctly updated for the new value. For instance, if your class has an attributes that must correspond to get accurate results - say for car braking system - then you can have a managed attribute that will automatically change the other attributes when it is changed. Thereby, you can ensure everything is correctly updated whenever this critical value changes. class Bar: def __init__(self): self._spam = 100 @property def spam(self): return self._spam @spam.setter def spam(self, value): print(self._spam) self._spam = value print(self._spam) @spam.getter def spam(self): return self._spam x = Bar() x.spam x.spam = 200 x.spam RE: TypeError: Not supported between instances of 'function' and 'int' - palladium - Dec-06-2019 Thank you guys for your help |