pythonif-statementswitch-statementperformanceprogram-flow

Python conversion calculator loop / code efficiency


The following is the (semi) finished version of a simple Mils to Degrees conversion calculator I built in Python 2.7 as a learning exercise. I am new to Python and still working out the kinks. The premise is, the user chooses to convert mils to degrees or vice versa. The user enters an azimuth of the chosen unit and it is converted to the other. If the user chooses an invalid menu option he is notified as such. If he enters an azimuth outside of the range (1-360 for degrees, 1-6400 for mils) he is notified and must start over. The problem is that if the user enters an invalid azimuth, say 365 degrees, he is kicked back to the menu. Is there a way to return to the previous step in the if/else loop? I've searched the forums and documentation and it doesn't appear to be possible. Also, since I'm new to Python, how can make this code more efficient? Do I need to have the if and elif statements in the function definitions or can I combine them without creating errors or redundant output? I've not been successful in doing so. All input is welcome and appreciated.

#Mil-Deg.py
#Simple Mils / Degrees Conversion Calculator
#6 JAN 2013

#Note: 6400 mils / 360 degrees in a circle. 17.78 mils to one degree.

import sys
import math
import winsound

#Define menu function
def menu():                     

    print 
    print " Mils / Degrees Conversion Calculator"
    print "-" * 38
    print 
    print "Options: "
    print "1. Degrees to Mils"
    print 
    print "2. Mils to Degrees"
    print 
    print "3. Quit"
    print "-" * 20
    print 
    return input ("Choose your option: ")
    print 

#Define mils to degrees function    
def m2d(a):
    if a <= 6400 and a >= 1:    #get user input within given range      
        b = 17.78
        c = round((a / b),0)    #convert and round to nearest degree  
        if c > 359 or c < 1:    #change 0 degrees to 360               
            c = 360
            #Output
            print
            print a, "mils =", int (c), "degrees"    
        else:
            print
            print a, "mils =", int (c), "degrees"
    elif a > -1 and a < 1:      #change 0 mils to 6400
        a = 6400
        b = 17.78
        c = round((a / b), 0)   #math, same as above
        if c > 359 or c < 1:    #0 to 360, same as above              
            c = 360
            #Output
            print
            print 6400, "mils =", int (c), "degrees"   
        else:
            print
            print a, "mils =", int (c), "degrees"
    else:
        #warning, mulligan
        winsound.Beep(440, 500)
        print 
        print "*** There are only 6400 mils in a circle. Try again. ***"
    print
    print "-" * 38
    print

#define degrees to mils function        
def d2m(b):
    if b <= 360 and b > 0:          #get user input within given range
        a = 17.78
        c = round((b * a),0)        #convert and round to nearest mil
        if c >= 6400:               #set limit to 6400 mils
            c = 6400
            #Output
            print
            print b, "degrees =", int (c), "mils"
        else:
            print
            print b, "degrees =", int (c), "mils"
    elif b > -1 and b < 1:          #change 0 to 360 degrees
        b = 360
        a = 17.78
        c = round((b * a),0)        #math, same as above
        if c >= 6400:
            c = 6400
            #Output
            print
            print 360, "degrees =", int (c), "mils"
        else:
            print
            print b, "degrees =", int (c), "mils"
    else:
        #warning
        winsound.Beep(440, 500)
        print 
        print "*** There are only 360 degrees in a circle. Try again. ***"
    print
    print "-" * 38
    print


#Begin program
loop = 1
choice = 0
while loop == 1:
    choice = menu()                 #Menu function call
    if choice == 1:                 #If user chooses degrees to mils:
        #Output
        print
        print "Enter your azimuth in degrees (1 - 360)"
        print 
        d2m(input("Degrees: "))     #function call

    elif choice == 2:               #If user chooses mils to degrees:
        #Output
        print
        print "Enter your azimuth in mils (1 - 6400)"
        print 
        m2d(input("Mils: "))        #function call

    elif choice == 3:               #If user chooses quit, exit program
        loop = 0

    elif choice != 1 and choice != 2 and choice != 3:   #if user makes invalid menu choice:
        #warning
        winsound.Beep(440, 500)
        print
        print
        print
        print choice, "is not a valid choice."
        print
        print "Please choose from the available options."
        print
        print

print 
print "-" * 38
print 
print "Thank you for using Mil-Deg.py"
print
print

Solution

  • I cleaned up your code a bit and made the following changes:

    1. Fixed your print statements
    2. Fixed your method names. Method names should be descriptive. Characters are free to type, so don't be stingy with typing out complete words.
    3. Your methods were printing output and duplicating logic, so I cleaned them up to just return the values instead. This way you can use these methods in other programs later on.
    4. Added a helper method to check user's input (to stop repeating/copy-pasting the same code again).
    5. I used the format function of strings to make it easy to print the calculations.

    Here is the result:

    import sys
    import math
    import winsound
    
    #Define menu function
    def menu():                     
        '''This function prints the main menu''' # this is a docstring for your method
        print "\nMils / Degrees Conversion Calculator"
        print "-" * 38
        print "\nOptions: "
        print "1. Degrees to Mils\n"
        print "2. Mils to Degrees\n"
        print "3. Quit\n"
        print "-" * 20
        print "\n"
    
    
    #Define mils to degrees function    
    def mils_to_degrees(a): # use method names that make sense
        '''This function takes mils and converts them into degrees'''
        b = 17.78
        c = round((a / b),0)    #convert and round to nearest degree  
        if c > 359 or c < 1:    #change 0 degrees to 360               
            c = 360
        return (a,int(c))
    
    #define degrees to mils function        
    def degrees_to_mils(b):
        '''This method converts degrees to mils'''
        a = 17.78
        if b == 0:
            b = 360
        c = round((b * a),0)        #math, same as above
        if c > 6400:               #set limit to 6400 mils
            c = 6400
        return (b,c)
    
    def check_input(user_input):
        '''Checks if the input is a number'''
        try:
            converted_number = int(user_input)
        except ValueError:
            return -1
        return converted_number
    
    #Begin program
    loop = True
    while loop:
        menu()
        choice = int(raw_input("Choose your option: "))
        if choice not in [1,2,3]:
            winsound.Beep(440, 500)
            print choice, "is not a valid choice.\n"
            print "Please choose from the available options.\n"
            menu()
            choice = int(raw_input('Choose your option: '))
    
        if choice == 1:
            print "\nEnter your azimuth in degrees (0 - 360)\n"
            degrees = check_input(raw_input('Degrees: '))
            if degrees > 360 or degrees < 0:
                print 'Please enter a value between 0 and 360'
            else:
                result = degrees_to_mils(degrees) # function call
                print '{} degrees = {} mils'.format(*result)
                print "-" * 38
    
        elif choice == 2:               #If user chooses mils to degrees:
            print "\nEnter your azimuth in mils (1 - 6400)\n"
            mils = check_input(raw_input('Mils: '))
            if mils > 6400 or mils < 1:
                print 'Please enter a value between 1 and 6400'
            else:
                result = mils_to_degrees(mils)        #function call
                print '{} mils = {} degrees'.format(*result)
                print "-" * 38
    
        elif choice == 3: 
            loop = False
    
    print "\n"
    print "-" * 38
    print "\nThank you for using Mil-Deg.py\n\n"