Struggling with While loops

Hello all.

I was working on a BMI calculator (practice: if, elif and else) and wanted to upgrade it with some while loops. But I am not sure I am on the right path, doing the right thing.
I inserted one while loop and it seems working. If I am making major mistakes I really would like to have some feedback on the proces. Inside the while loop I inserted another while loop. But it is flipping back to the first while loop (Hope you can understand me, I am completly new at this (Think 4th week of the 100 days coding challenge.)) All help and advice is welcome.

gender = input('Is youre gender (M)ale or (F)emale?: ')
gender_male = "M"
gender_female = "F"
answer_yes = "Y"
answer_no = "N"
wrong_answer = "We don't understand you. Please insert (Y)es or (N)o."
advice_low_BMI = ("""
1. Eat at least five portions a day.
2. Eat food that contains carbohydrates.
3. Having some dairy or dairy alternatives.
4. Eating some beans, pulses, fish, eggs, meat and other protein.
        """)
advice_high_BMI = ("""
1. Eat less food. 
2. Eat at set times.
3. Excercise.
4. Don't eat food before going to bed. 
        """)
no_advice_wanted = ("We wish you luck on youre journey to gain a healthy BMI-score.")
wrong_insert = ("We dont understand you. Please insert (Y)es or (N)o.")



while gender.upper() == gender_male or gender_female:
     if gender == gender_male:
        weight_male = float(input('What is youre weight (kg)?: '))
        height_male = float(input('What is youre height (m)?: '))
        BMI_male = weight_male/(height_male**2)
        BMI_str_male = round (BMI_male,1)
        if BMI_male > 25: 
            print (f'The BMI-score is: {BMI_str_male}. You have overweight. Do you need advice on healthy life changes?')
            answer_high_BMI =  input('Please insert: (Y)es or (N)o: ') 
            while answer_high_BMI == answer_yes:
                print (advice_high_BMI)
                break
            if answer_high_BMI == answer_no:
                print (no_advice_wanted)
                break
            else: 
                print(wrong_insert)
                answer_high_BMI =  input('Please insert: (Y)es or (N)o: ')
                while answer_high_BMI == answer_yes:
                    print (advice_high_BMI)
                    break
                if answer_high_BMI == answer_no:
                    print (no_advice_wanted)
                    break        
        elif BMI_male < 18:
            print (f'The BMI-score is: {BMI_str_male}. You have underweight. Do you need advice on healthy life changes?')
            print ('Please insert: (Y)es or (N)o: ')
        else: 
            print (f"The BMI-score is: {BMI_str_male}. You're BMI is perfect.")
            break 
     elif gender == gender_female:
        print('We will calculate the BMI-score for the female gender.')
        weight_female = float(input('What is youre weight (kg)?: '))
        height_female = float(input('What is youre height (m)?: '))
        BMI_female = weight_female/(height_female**2)
        BMI_str_female = round (BMI_female,1)
        if BMI_female > 25: 
            print (f'The BMI-score is: {BMI_str_female}. You have overweight. Do you need advice on healthy life changes?')
            print ('Please insert: (Y)es or (N)o: ')
        elif BMI_female < 18:
            print (f'The BMI-score is: {BMI_str_female}. You have underweight. Do you need advice on healthy life changes?')
            print ('Please insert: (Y)es or (N)o: ')
        else: 
            print (f"The BMI-score is: {BMI_str_female}. You're BMI is perfect.")
            break
     else: 
        print("Sorry we dont understand you. Please insert capital (M) or (F).")
        gender = input('Is youre gender (M)ale or (F)emale?: ')
type or paste code here

Let’s start at the top.

You could do something like this:

genders = ("m", "f")

gender = ""
while gender not in genders:
    gender = input('Is youre gender (M)ale or (F)emale?: ').lower()

… and use the same technique for the other user inputs.

Ta add…

The next thing I would do, is the gather all the user inputs (or data) in the first part of the script, then analyze the data, then finally produce and present the results.

Furthermore, by constructing your code in a logical way, it will be easier to maintain and you may also begin to see where you could use a custom function or two.

1 Like

Let’s walk through your code and identify some problems.

while gender.upper() == gender_male or gender_female:

This is always True, because the == operator has higher priority than or, and because boolean operators are not distributive.

A non-empty string has a boolean value of True in Python, so the expression is equivalent to (gender.upper() == gender_male) or True, which in turn is equivalent to True.

Next:

                while answer_high_BMI == answer_yes:
                    print (advice_high_BMI)
                    break

This will never loop, because the break is reached unconditionally.

Therefore, this next break in the if clause:

                if answer_high_BMI == answer_no:
                    print (no_advice_wanted)
                    break        

actually breaks out of the first while loop, which I don’t think was your intention.

A more general piece of advice, your program has way too many code paths. It’s quite difficult to follow all the branches. Avoid nesting multiple levels of if and while. Limit yourself to a single while with a single if clause in it. If you need more levels, put them inside functions and call them from the main loop.

2 Likes

I would try to define steps in natural language and then start coding.

One way to decompose the problem into smaller tasks:

  • ask from user gender and validate it
  • ask from user weight and validate it
  • ask from user height and validate it
  • calculate BMI
  • display BMI and its assessment
  • display advice based on BMI

As one can see there are three user input validations (gender, weight, height) and this is indication to use function. If you are familiar with functions you should try to write one. If not then something like this could be written:

while (answer := input("Please enter your gender (F or M): ").lower()) not in ("m", "f"):
    print(f"Expected F or M but you entered {answer!r}")

As far as I know the formula and brackets are the same for M and F so gender is actually not needed while calculating BMI and making assessment.

1 Like

Thanks allot Rob.
I sure will try this.

Thanks for the advice.
This answer I need to do some study on.
But it will work better for sure.
Think I need to do some different thinking while coding.

Thats some good advice.
When making a plan in natural language it gives more overview when you start coding.
As I see back on the proces I started to miss my overview.

I used youre advice. But I am loosing it overhere. Cant get a grip on this coding.
I now wrote this code. But it isnt corresponding with eachother and I cant see what I am doing wrong anymore (little frustrated).

gender = ("M" or "F")
genders = ""


while gender not in genders: 
    input ('Is youre gender (M)ale or (F)emale?: ').upper()
    weight = float(input('What is youre weight (kg)?: '))
    height = float(input('What is youre height (m)?: '))
    BMI = weight/(height**2)
    BMI_str = round(BMI,1)
    if  gender == "M" and BMI > 22:
        print(f"You're BMI is score is {BMI_str},for a male you're to heavy.")
    elif gender == "F" and BMI >25:
        print(f"You're BMI is score is {BMI_str},for a female you're to heavy.")
    elif gender == "M" and BMI < 18.5:
        print(f"You're BMI is score is {BMI_str}, for a male you have underweight.")
    elif gender == "F" and BMI < 18.5:
        print(f"You're BMI is score is {BMI_str}, for a female you have underweight.")
    else:
        print("You're weight is perfect.")

I see problems right at the beginning of your code. Here are questions to direct you to resolve them:

  • Do the variable names gender and genders correspond to their content?
  • What does gender contain after the first line is executed? Is it what it is supposed to contain?
  • What do you do with the result of the first input()?

I was not checking the code beyond the first input() because there was enough of problems already. Suggestion: Why do not you make one functionality working before you add another one?

2 Likes

This code line:

… is doing nothing.

Also (and I think it’s because you’re trying to get to grips with English as well as Python) ‘gender’ and ‘genders’ is the wrong way around: ‘genders’ is the plural ‘gender’, so…

genders = ("M", "F") # you don't need the 'or'; this is a Tuple: there are two genders.
gender = "" # this is what needs to be checked in the while loop
while gender not in genders:
    gender = input('Is your gender (M)ale or (F)emale?: ').upper()
    # now the rest of your code

Others have posted some good advice, so take note of it.

[edit to correct a typo]


Just to add…

Technically an empty input, as in input("Press enter to continue.") in fact does not do nothing: it will simply hold the script at the input, until the enter key is pressed, but it returns None, which is why you need something = input("Whatever: ") if you want your script to use whatever it is that has been entered.

1 Like

On top of plan you may choose to write code by incrementing it. For example, first iteration to calculate BMI:

gender = input('Please input your gender (F or M): ')
weight = float(input('Please enter your weight: '))
height = float(input('Pease enter your height in centimeters: '))

bmi = weight/((height/100)**2)

print(bmi)

This code calculates BMI as long as input is correct. Now you can add more functionality - assessment. As stated at the beginning the objective was to practice if, elif, else, so no dictionaries or whatnot:

if bmi < 18:
    print('You are underweight')
elif bmi < 25:
    print('Your BMI is perfect')
else:
    print('You are overweight')

This also works as expected if correct input is provided. Now we could add validation by replacing first row with:

while (answer := input("Please enter your gender (F or M): ").lower()) not in ("m", "f"):
    print(f"Expected F or M but you entered {answer!r}")

User can get past this only then F/f or M/m is provided.

For weight we should have other limitations. In order it to be real, it must be more than 0. We should/could also set upper boundary. Following code tries to convert user input into float, if this fails ValueError will be raised by Python; same error will be raised by code itself if value is not within boundaries:

while True:
    answer = input('Please enter your weight: ')
    try:
        weight = float(answer)
        if 0 < weight < 300:
            break                       # everything is OK; break out of while loop
        else:
            raise ValueError
    except ValueError:
        print(f'Expected value in range 0...299 but your answer was {answer!r}')

Similar approach could be used for height.

Add health advice and your program should work.

Then of course you will notice that there are lot of repetitions. So you refactor your code once more :slight_smile:

You are doing well cybe. I know how frustrated you feel and a lot of information you can find in the internet looks like it will help but then it just trips you up.

I spent 8 hours today (most of them wanting to smash my pc) trying to refine a program for my TAFE course. One place I find to be very helpful is the actual Python docs website and if that doesn’t work then this forum.

Try to avoid taking snippets of code from other places. Just keep it simple and when you have the whole thing working then spice the code up.

Oh and one more thing always copy and paste your code in to a new file before making any changes to a working version. Sometimes you can’t go back and undo the mess you have just typed :joy:

Thank you so much for this nice comment.
Think I needed this message to get on going.
It was to much information and for myself I was missing links of knowledge to understand the theorie fully.
I will start all over and dive into the Python docs.

Everyone thanks allot for youre help!!

1 Like