Python Forum
TypeError: Not supported between instances of 'function' and 'int'
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
TypeError: Not supported between instances of 'function' and 'int'
#1
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:

Error:
PS D:\python\framingham> python framingham.py Please enter total cholesterol. 5 Please enter HDL cholesterol. 1 Traceback (most recent call last): File "framingham.py", line 32, in <module> highrisk(variables.age, variables.diabetes, variables.systolic_blood_pressure, variables.total_cholesterol) File "framingham.py", line 16, in __init__ elif systolic_blood_pressure >= 180: TypeError: '>=' not supported between instances of 'function' and 'int'
I thought the eval() function already converts the string to int/float?

Some help would be much appreciated. Thanks
Reply
#2
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 eval
b = float(input("Please enter SBP: "))
Reply
#3
Thanks so much for your help!
Reply
#4
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:

Error:
Traceback (most recent call last): File "framingham.py", line 82, in <module> genderassignment() File "framingham.py", line 46, in genderassignment print(f"Your five year risk is: {risk_calculator_male()}% .") File "framingham.py", line 20, in risk_calculator_male mu1 = common.mu1() File "framingham.py", line 11, in mu1 mu1 = 4.4181+m NameError: name 'm' is not defined
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.
Reply
#5
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()
Reply
#6
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?
Reply
#7
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?
Reply
#8
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
100
line 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)...
Reply
#9
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
Reply
#10
Thank you guys for your help
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Using curve_fit to optimize function (TypeError) Laplace12 4 2,454 Aug-30-2021, 11:15 AM
Last Post: Larz60+
  [Solved] TypeError when calling function Laplace12 2 2,832 Jun-16-2021, 02:46 PM
Last Post: Laplace12
  Sort Function: <' not supported between instances of 'float' and 'tuple' quest 2 7,972 Apr-30-2021, 07:37 PM
Last Post: quest
Exclamation TypeError: '>=' not supported between instances of 'int' and 'str' helpme1 11 8,678 Mar-11-2021, 11:13 AM
Last Post: helpme1
  Type error: '>' not supported between instances of 'NoneType' and 'int' spalisetty06 1 10,427 Apr-29-2020, 06:41 AM
Last Post: buran
  TypeError: '<' not supported between instances of 'str' and 'int' Svensation 5 8,671 Jan-20-2020, 08:12 PM
Last Post: buran
  TypeError: '>=' not supported between instances of 'str' and 'int' AsadZ 8 10,340 Aug-20-2019, 11:45 AM
Last Post: ThomasL
  '>' not supported between instances of 'str' and 'int' graham23s 2 3,927 May-11-2019, 07:09 PM
Last Post: micseydel
  Newbie Question re "TypeError: '<' not supported between instances of 'list' and 'int sr12 8 12,947 Apr-11-2019, 08:19 PM
Last Post: sr12
  '<' not supported between instances of 'str' and 'int' jayaherkar 1 7,904 Apr-09-2019, 03:25 PM
Last Post: perfringo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020