Josh Chingas
Josh Chingas

Reputation: 21

How to properly run a method within a method in a class (python)

def main():

class BMI:

    def __init__(self, firstName, lastName, age, height, weight):
        self.firstName = firstName
        self.lastName = lastName
        self.fullName = firstName + " " + lastName
        self.age = age
        self.height = (height * 0.025) ** 2
        self.weight = weight * 0.45

    def setFullName(self, firstName, lastName):
        self.firstName = firstName
        self.lastName = lastName
        self.fullName = firstName + " " + lastName

        print(self.fullName)

    def setAge(self, age):
        self.age = age

    def setHeight(self, height):
        self.height = (height * 0.025) ** 2

    def setWeight(self, weight):
        self.weight = weight * 0.45

    def getBMI(self):
        bmi = self.weight // self.height
        return bmi

    def getStatus(self):

        getBMI()

        if bmi < 19:
            print("You have an unhealthy BMI, gain some weight!")
        elif bmi > 19 and bmi < 25:
            print("You have a healthy BMI")
        else:
            print("You have an unhealthy BMI, lose some weight!")


firstName = input("Enter your first name: ")

lastName = input("Enter your last name: ")

age = int(input("Enter your age: "))

height = int(input("Enter your height in inches: "))

weight = int(input("Enter your weight in lbs: "))

userInputBMI = BMI(firstName, lastName, age, height, weight)


print(userInputBMI.setFullName(firstName, lastName))

print("Your BMI is:", userInputBMI.getBMI())

print(userInputBMI.getStatus())

main()

My problem is printing the status of the user based on the inputs they provide. The problem is coming from the method being run within the "getStatus" method.

My thoughts are that from that method within the "getStatus" it gets the bmi that is measured within the if-elif-else statements. The computer says that "getBMI" is not defined. If someone could teach me the right way to use methods how I am trying that would be awesome!

Upvotes: 2

Views: 353

Answers (2)

Alex Lopatin
Alex Lopatin

Reputation: 692

change the line:

    getBMI()

to

    bmi = self.getBMI()

I have years of experience in programming, but I am learning Python as a new language as you too. Correct me anybody, please, if I am wrong or you have something to add. Here are my suggestion of the right way to use methods and the language:

  1. Read about Python naming convention: function names and variables are lowercase, method and instance variables too.
  2. No need to pre-calculate and have instance variable full_name: just calculate and return it when you need one.
  3. Don’t convert height to some part of the square height formula and keep it under name height. Just calculate BMI from height and weight when you need it and by BMI formula from inches and pounds.
  4. Keep the calculation result in float since they use not 19, but 18.5 as threshold value.
  5. No need to provide setAge, setHeight, setWeight in your code question, since you don’t need and don’t use it in the program yet. Actually, if you think: set_height, and set_weight (Python naming) you don’t need to provide at all. You create the person instance and it stays constant. Same probably with set_age, until you not creating some simulation game when your instances will age.
  6. Print should be outside your class. You ask for value or string to be returned if you need something to display or print.
  7. Last, but not least: think immediately about testing and write test function first. It is very boring to enter a first name, last name, age, height, and weight ... again, and again … QA will reuse your test later for unit testing.

Here is my suggestion in the form of code (I left one bug intentionally - I think it will be easy to catch. Sorry, if more than one - nobody is perfect):

class BodyMassIndex:

    BMI_STATUS_LOSE = 0
    BMI_STATUS_HEALTHY = 1
    BMI_STATUS_GAIN = 2

    def __init__(self, first_name, last_name, age, height, weight):
        self._first_name = first_name
        self._last_name = last_name
        self._age = age
        self._height = height
        self._weight = weight

    def get_full_name(self):
        return self._first_name + " " + self._last_name

    def get_bmi(self):
        return (self._weight * 703) / self._height ** 2

    def get_status(self):
        bmi = self.get_bmi()
        if bmi < 18.5:
            status = BodyMassIndex.BMI_STATUS_LOSE
        elif bmi < 25.0:
            status = BodyMassIndex.BMI_STATUS_HEALTHY
        else:
            status = BodyMassIndex.BMI_STATUS_GAIN
        return status

    def get_report(self):
        a = self.get_full_name()
        b = "Your BMI is: {0:.1f}".format(self.get_bmi())
        status_name = ['n unhealthy BMI, lose some weight!',
                       ' healthy BMI',
                       'n unhealthy BMI, gain some weight!']
        c = 'You have a' + status_name[self.get_status()]
        return a + '\n' + b + '\n' + c


if __name__ == '__main__':

    def first_test():
        user_test_list = [
            ("Alex", "Fat",    21, 69, 170, 2),
            ("Josh", "Smart",  17, 69, 169, 1),
            ("Ann", "Full",    19, 69, 126, 1),
            ("Mary", "Skinny", 19, 69, 125, 0),
        ]
        for first, last, age, height, weight, expected in user_test_list:
            user = BodyMassIndex(first, last, age, height, weight)
            print(user.get_report())
            print()

    first_test()

    while True:
        first = input("Enter your first name: ")
        if not first:
            break
        last = input("Enter your last name: ")
        age = int(input("Enter your age: "))
        height = int(input("Enter your height in inches: "))
        weight = int(input("Enter your weight in lbs: "))
        user = BodyMassIndex(first, last, age, height, weight)
        print(user.get_report())

Upvotes: 1

jfaccioni
jfaccioni

Reputation: 7509

You need to tell Python that, inside your getStatus method, you want to access your getBMI method from the same class, and not a function (or any other callable object) named getBMI that's defined outside of your class. You do this by referencing the method as self.getBMI inside your class, like this:

def getStatus(self): 

    bmi = self.getBMI()

Notice that I also caught the return value of getBMI, because otherwise that value is lost. bmi is just a local variable inside the getBMI method which will be forgotten once it ends, unless you either:

  • return that value and catch the return with another variable upon executing the method;
  • save it as an instance attribute, writing (at some point) self.bmi = bmi inside your getBMI method.

I'd go with the first option, since it makes sense for a method named getBMI to return the bmi. It's also a bit easier to mess up and forget which attribute is which if you constantly write and rewrite the instance attributes - tho sometimes that's exactly why you would use objects and classes in the first place.

Upvotes: 1

Related Questions