3
\$\begingroup\$

This is my first attempt at writing a programme: a BMI calculator written in Python. Please give me feedback on the programme overall, as well as how easy the code is to interpret and adapt.

from sys import exit

bmi = ["what is bmi?", "what is bmi", "bmi", "bmi?"]

male=["male","m"]

female=["female", "f"]

def bmi_q():
    print "Very good! Let's start with your age."
    age= float(raw_input("How old are you %s?   >   " %name))

    height= float(raw_input("How tall are you, in m?    >   "))

    weight=float(raw_input("What do you weigh in kg?    >   "))
    Gender=raw_input("Finally, are you male or female? (No offense.)    >   ")

    result = bmi_c(weight,height)

    analysis(result)

def analysis(result):
    if result < 18.5:
        print "Your BMI is %d." % round(result,2), "You are far too skinny, please eat more." 
        print "A healthy BMI is between 18.5 and 25."
        exit(0)

    elif result > 25:
        print "Your BMI is %d." % round(result,2), "You are far too fat, please eat less." 
        print "A healthy BMI is between 18.5 and 25."
        exit(0)

    else:
        print "Your BMI is %d." % round(result,2), "Congratulations! You're well fit."
        print "A healthy BMI is between 18.5 and 25."
        exit(0)

def bmi_c(weight,height):
    return weight / (height**2)

def consent_q():    
    unsure = True

    while True:
        print "Would you like to calculate your BMI?" 
        consent = raw_input("> Answer: \"Yes\", \"No\", or \"What is BMI?\" >   ")

        if consent.lower() == "no":
            print ("What did you open a script called \"BMI\" for then??? This is all I can do!")

        elif consent.lower() in bmi:
            print """Wise man at CDC say: 
                \"Body Mass Index (BMI) is a person's weight in kilograms 
                divided by the square of height in meters. 

                A high BMI can be an indicator of high body fatness. 

                BMI can be used to screen for weight categories that may 
                lead to health problems but it is not diagnostic of the 
                body fatness or health of an individual.\" """

        elif consent.lower() == "yes":
            unsure = False
            bmi_q()

        else:
            print "Sorry, me no hablo ingles so good. Try again."


print "Thank you for running the BMI script." 
print "Before we begin, please tell me your name:"
name=raw_input(">   ")
print "Hello %s, nice to meet you." % (name)
consent_q()
\$\endgroup\$
1
  • \$\begingroup\$ This was flagged as off-topic but I don't see anything obviously broken about this, so voting to leave open. \$\endgroup\$ Aug 11, 2016 at 3:30

3 Answers 3

4
\$\begingroup\$

The main issue I see is inconsistent style. Sometimes you put spaces around certain operators, sometimes you don't. You want your code to be consistently formatted.

Generally, it's best to always put a space before and after an operator, especially the assignment operator. It's even more strange to put a space before an operator, but not after (or vice versa).

This line, for example:

age= float(raw_input("How old are you %s?   >   " %name))

would look much better like this:

age = float(raw_input("How old are you %s?   >   " % name))

You also switch between putting a space after commas in lists, and not doing so. I would change these lines:

male=["male","m"]

female=["female", "f"]

to look like this (notice the space after the first comma):

male = ["male", "m"]

female = ["female", "f"]

Variables should always begin with a lowercase letter. Classes and constants can and should be capitalized, but not normal variables. So the Gender variable should be renamed to gender.

You should consider not asking for the user's gender and age unless you actually do something with that data, or at least don't assign it to variables because it'll go unused.

I would also rename bmi_q, bmi_c, and consent_q to something more clear, so other people reading your code can immediately know what those function are supposed to do. bmi_c could definitely be renamed to something like calculate_bmi, or even calc_bmi.

And lastly, I'd always make sure your indention doesn't get messed up when pasting your code into a site like this. There's a few problems with invalid indention, but I'd imaging that happened when you put it in this question. (the indention in the question has been fixed now though)

But overall, good job on writing your first program! Congrats, keep it up, and remember this quote from Phil Karlton:

There are only two hard things in Computer Science: cache invalidation and naming things.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Worth mentioning that you should never declare variables that you don't use. gender and age are one of those cases where they should be used or deleted. \$\endgroup\$
    – Trojan404
    Aug 10, 2016 at 19:55
  • 4
    \$\begingroup\$ Two hard things: naming things, cache invalidation, and off-by-one errors ;-) \$\endgroup\$ Aug 10, 2016 at 20:14
  • \$\begingroup\$ Thanks for this, there's a lot here for me to build on and I appreciate it. One thing that I want to make sure of is that my code makes sense to other people. Clear formatting and sensible names should help a lot. I'll be using those variables later when I take this programme further, but I agree that there's no need for them here so I should take them out. Thanks as well to whoever fixed the code for my post. :) \$\endgroup\$ Aug 11, 2016 at 10:38
3
\$\begingroup\$

One important thing to learn early on, is to never trust a user's input.

I don't do , but I believe this:

height= float(raw_input("How tall are you, in m?    >   "))

Would throw an exception (or otherwise blow up, if there are no exceptions in that language), if the user enters a value that can't be converted to a float, say "foobar". Or it might evaluate to 0, in which case...

def bmi_c(weight,height):
     return weight / (height**2)

Would definitely blow up with some division by zero error.

QA engineer walks into a bar. Orders a beer. Orders 0 beers. Orders 999999999 beers. Orders a lizard. Orders -1 beers. Orders a sfdeljknesv.

https://twitter.com/JimFraeErskine/status/527564769302433792

You should always [at least minimally] validate user input before you pass it along to the rest of your program.


print "Your BMI is %d." % round(result,2), "You are far too fat, please eat less." 

Well there's an opportunity to use that unused gender variable and output a ...kinder message to ladies :)

\$\endgroup\$
2
  • \$\begingroup\$ For the record, Python is very capable of throwing exceptions. It won't make JavaScript-style assumptions, if it can't be turned into a float it will definitely throw. I suspect a ValueError will be thrown since it's an invalid literal. This could be caught with a try except block. \$\endgroup\$
    – Mast
    Aug 11, 2016 at 8:59
  • \$\begingroup\$ Good call. I was going to use age and gender later to give a more accurate BMI, but changing the responses is a good idea too. I've not used try except before, but it looks like something I should build on. Thanks for that. \$\endgroup\$ Aug 11, 2016 at 10:33
1
\$\begingroup\$

Adding to what addison said:

  1. No need for variable result just write:analysis(bmi_c(weight, height))
  2. I'm unsure what variable unsure is used for :)
  3. Try to extract things when they are common, e.g.

    print "A healthy BMI is between 18.5 and 25." exit(0)

I think you should extract those two statements outside of ifs. Also I would get rid of exit(0).

Congrats on your first program!

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.