1
\$\begingroup\$

I'm very very fresh to programming. This is one of my first experiments with Python and I'm wondering in what ways I could have made this program less clunky. Specifically, is there a way that I could have used classes instead of defining my x, y, and z variables globally?

def getx():
    try:
        global x
        x = float(raw_input("Please give your weight (pounds): "))
        return x
    except ValueError:
        print("Use a number, silly!")
        getx()
def gety():
    try:
        global y
        y = float(raw_input("what is your current body fat percentage? (>1): "))
        return y
    except ValueError:
        print("Use a number, silly!")
        gety()
def getz():
    try:
        global z
        z = float(raw_input("What is your desired body fat percentage? (>1): "))
        return z
    except ValueError:
        print("Use a number, silly!")
        getz()
def output():
    getx()
    gety()
    getz()
    A = (x*(y/100-z/100))/(1-z/100)
    B = x - A
    print("Your necessary weight loss is %.1f pounds, and \
your final weight will be %.1f pounds" % (A,B))
    more()
def more():
    again = raw_input("Calculate again? ")
    if again.lower() == "yes" or \
       again.lower() == "y" or \
       again.lower() == "sure" or \
       again.lower() == "ok" or \
       again.lower() == "" or \
       again.lower() == "okay":
        output()
    elif again.lower() == "no" or \
         again.lower() == "n" or \
         again.lower() == "nah" or \
         again.lower() == "nope":
            end()
    else:
        more()
def end():
    print("Ok, see ya later!")
output()
\$\endgroup\$
  • 1
    \$\begingroup\$ This belongs on codereview, but I don't see how classes would help. You might want to get rid of the global variables, however and just pass things in via function arguments. \$\endgroup\$ – Joel Cornett Aug 9 '12 at 19:50
  • \$\begingroup\$ since all three "get" functions are almost identical, you can reduce them to one that takes a parameter for the input prompt. For the if statements, you can say ... if again.lower() in ["yes", "y", ...]: \$\endgroup\$ – jcfollower Aug 9 '12 at 19:56
4
\$\begingroup\$

all of your functions seem to do the same thing with a different message, so why not condense them and take the message as a parameter?

def get_num(msg):
    num = None
    while num is None:
        try:
            num = float(raw_input(msg))
        except ValueError:
            print("Use a number, silly!")

    return num

and then

def output():
    x = get_num('Please give your weight (pounds): ')
    y = get_num('what is your current body fat percentage? (>1): ')
    z = get_num('What is your desired body fat percentage? (>1): ')
    A = (x*(y/100-z/100))/(1-z/100)
    B = x - A
    print("Your necessary weight loss is %.1f pounds, and \
your final weight will be %.1f pounds" % (A,B))
    more()

in your more function you can condense your ifs with the in operator

def more():
    again = raw_input("Calculate again? ")

    if again.lower() in ["yes", "y", "sure" , "ok", "", "okay"]:
        output()
    elif again.lower() in ["no", "n", "nah", "nope"]:
        end()
    else:
        more()
\$\endgroup\$
1
\$\begingroup\$

Do you have objects, "things" that have state and behaviour? I don't see any. So use functions as you do (perhaps improve the code format).

\$\endgroup\$
1
\$\begingroup\$

In getx, gety and getz there's no need to use global and return. Also, it would be better to use iteration rather than recursion, like this:

def getx():
    while True:
        try:
            return float(raw_input("Please give your weight (pounds): "))
        except ValueError:
            print("Use a number, silly!")

You might also want to use better function and variable names.

\$\endgroup\$
0
\$\begingroup\$

Yes, you definitely can. You can try something in the lines of:

class PersonData(object):
  def __init__(self):
    pass


  def getx(self):
    try:
        self.x = float(raw_input("Please give your weight (pounds): "))
    except ValueError:
        print("Use a number, silly!")
        self.getx()

.. and so on.

And then in your main program:

if __name__ == "__main__":
  person = PersonData()
  person.getx()
  person.gety()

... 

  A = (person.x * (person.y / 100 - person.z / 100))/(1 - person.z / 100)

If you get my drift. This is generally if you want to use classes. Otherwise see other answers :)

\$\endgroup\$
0
\$\begingroup\$

The code below condenses your script (fewer lines and redundancy when you remove the triple quote explanations). Honestly, using classes would complicate your function, so unless you need the classes for something else, just do all in the function. Also, typically it is better to not call globals unless you need to. For your purpose, unless there is more to the script, use local variables.

Your script suffers a lot from redundancy. It works fine, but there are easier ways to do it. Instead of reusing again.lower() ==, put all the desired responses into a list. Using 'is...in' checks if your variable is in you list (or string, etc). For example, if var in ["y", "yes"]:

You can further reduce your redundancy by making a function to do your try/except statements, but I used while statements to show another way to do it. You can then use continue (which resets back to the beginning) if there is an exception and use break to exit the loop if you try statement succeeds.

Note: I tested this on Pythonista for iOS using 2.7. I added in the triple quotes as explanations after confirming the script worked and using as is may throw an indentation error. Removing the triple quote explanations should run it properly.

""" Unless you are reusing variables, but it all in 
the same function"""

def output():
""" Put your inputs in a while statement. Continue on
exception and break otherwise"""
    while True:
      try:
         x = float(raw_input("Please give your weight (pounds): "))
      except ValueError:
          print("Use a number, silly!")
          continue
      break
    while True:
      try:
          y = float(raw_input("what is your current body fat percentage? (>1): "))
      except ValueError:
          print("Use a number, silly!")
          continue
      break
    while True:
      try:
          z = float(raw_input("What is your desired body fat percentage? (>1): "))
      except ValueError:
         print("Use a number, silly!")
         continue
      break
    A = (x*(y/100-z/100))/(1-z/100)
    B = x - A
    print("Your necessary weight loss is %.1f pounds, and \
your final weight will be %.1f pounds" % (A,B))

""" Like before put input into while statement"""

    while True:
      again = raw_input("Calculate again? ")

""" Condense your input options into an if in statement"""
      if again.lower() in ["yes", "y", "sure", "ok", "", "okay"]:
        output()

""" Unless No response is important, just use else
catchall"""
      else:
        print("Ok, see ya later!")
        break
output()
\$\endgroup\$
  • 1
    \$\begingroup\$ How and why does this condense the original script? Can you explain why you did the things you did? \$\endgroup\$ – Stephen Rauch Apr 19 '17 at 17:36
  • \$\begingroup\$ Also, please verify your indentation. \$\endgroup\$ – 200_success Apr 19 '17 at 18:13
  • \$\begingroup\$ @StephenRauch It's fewer lines and less redundancy. For example, instead of rewriting each "again.lower() ==" line, it puts all desirable responses into a list and checks if the response is in the list. Unless 'No' is very important, any answer that isn't yes can be 'No' - otherwise, put in a list and check. I explained my changes inside of the script. The while statements removes the need for separate functions. Continue runs the previous try and break ends the statement. This can be further condensed, but I wanted to show the while/continue/break combination with try/except. \$\endgroup\$ – Superspork Apr 19 '17 at 18:51
  • \$\begingroup\$ @200_success I wrote this on Pythonista on my phone, so indentation may be off compared to desktop version. Also, I added the notes explaining changes after I verified the function worked and the notes are throwing me the indentation errors. Remove the triple quote notes and it all runs fine. \$\endgroup\$ – Superspork Apr 19 '17 at 18:53
  • \$\begingroup\$ Thanks for the feedback, but you should edit this explanation into the answer so that it is helpful for future readers. Thanks. \$\endgroup\$ – Stephen Rauch Apr 19 '17 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy