3

How can I get rid of the excessive repetition in this code?

Code: http://pastebin.com/13e2nWM9

The program calculates equations of motion (SUVAT Equations) based on data provided by the user.

The section I refer to is:

while True:
        a = raw_input("What is the value of a? Make sure it is in standard units, however, do not include the unit.")
        try:
            float(a)
            print "a is " + str(a) + " ms^-2"
            break
        except:
            print"You must enter a number. Don't include units!"

This is repeated many times, save for the variable 'a' and the unit which changes when the block is repeated.

Many thanks.

Pavel Anossov
  • 60,842
  • 14
  • 151
  • 124
Ricochet_Bunny
  • 537
  • 3
  • 8
  • 19
  • It can be more pythonic, but why is this code not efficient enough? It is just an assignment and a cast to a float - there is no much room for improvement here. – A. Rodas Apr 11 '13 at 23:35
  • 2
    I can see no reason that this code would have any need, or infact, any use at all, for extra efficency. The limiting factor here is the speed of the console output. – AJMansfield Apr 11 '13 at 23:37
  • 4
    For the biggest speedup add blinking lights and dramatic music to make the user type faster. – Jochen Ritzel Apr 11 '13 at 23:37
  • 1
    So no one noticed the link to actual code? You're missing out. – Pavel Anossov Apr 11 '13 at 23:38
  • @JochenRitzel That's too funny. :D – squiguy Apr 11 '13 at 23:41
  • I assumed that if there was a way to define a function that would do the same thing as that block of code, I would be able to vastly reduce the number of lines of the code, and therefore take up less storage space. Maybe 'efficient' was the wrong word? – Ricochet_Bunny Apr 11 '13 at 23:54

4 Answers4

3

Here is one option, put the following function definition at the top of your module:

def get_float(name, units):
    prompt = "What is the value of {0}? Make sure it is in standard units, however, do not include the unit.".format(name)
    while True:
        val = raw_input(prompt)
        try:
            val = float(val)
            print '{0} is {1} {2}'.format(name, val, units)
            return val
        except Exception:
            print "You must enter a number. Don't include units!"

Here is an example of how you could use it, the following code could replace everything from line 72 to 100:

name_units_pairs = [('v', 'ms^-1'), ('a', 'ms^-2'), ('t', 's'),]
vals = {}
for name, units in name_units_pairs:
    vals[name] = get_float(name, units)
u = vals['v'] - vals['a'] * vals['t']
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
1

Do not use raw excepts, and encapsulate the tests, that is all. So instead of

while True:
        a = raw_input("What is the value of a? Make sure it is in standard units, however, do not include the unit.")
        try:
            float(a)
            print "a is " + str(a) + " ms^-2"
            break
        except:
            print"You must enter a number. Don't include units!"

do

a = my_input(valuename='a', unit='m^-2', unitformat=float)

and do the tests (and prompts) in my_input.

my_input may look something like:

def my_input(valuename, unit, unitformat=float):
  while True:
    val = raw_input("What is the value of %s? Make sure it is in standard units"+
                    "(%s), however, do not include the unit." % (valuename, unit))
    try:
        unitformat(val)
    except ValueError:
        print"You must enter a number. Don't include units!"
    else:
        print "%s is %s %s" % (valuename, val, unit)
        return val
ch3ka
  • 11,792
  • 4
  • 31
  • 28
0

I can see no reason that this code would have any need, or infact, any use at all, for extra efficency. The limiting factor here is the speed of the console output.

But...

If the extra few nanoseconds it saves you is really, REALLY important, somehow, the biggest way you can speed it up (I think, although it may actually slow it down because of the interpreting) is to output the printed stuff seperately, in different print statements, so it doesn't have to construct 2 extra strings in memory to represent the values of "a is " + str(a) and "a is " + str(a) + " ms^-2". To save another few nanoseconds, write the program in a language that gets compiled to machine code.

Or, if you mean using less code to do the same thing, encapsulate the input, like the others are saying.

AJMansfield
  • 4,039
  • 3
  • 29
  • 50
0

You can use loops to automate the input, storing the values in a dictionary, then do all the maths at the end.

import math

units = {'s': 'm', 'u': 'ms^-1', 'v': 'ms^-1', 'a': 'ms^-2', 't': 's'}
variables = ['s', 'u', 'v', 'a', 't']
suvat = dict((k, None) for k in variables)
input_variables = []

def pick_from_list(prompt, L):
    while True:
        pick = raw_input(prompt % str(L))
        if pick in L:
            print "You have chosen", pick
            return pick
        print """Sorry, I didn't understand that, try again. Make sure your spelling is
            correct (Case Sensitive), and that you did not inlcude the quotation marks."""

aim = pick_from_list("""Welcome to Mattin's SUVAT Simulator! Choose the value you are
                    trying to find. You can pick from variables %s""",
                     variables)

for order in 'first', 'second', 'third':
    prompt = 'Please choose which variable to input %s. You can pick from %%s' % order
    choices = [k for k in variables if not (k is aim or k in input_variables)]
    input_variables.append(pick_from_list(prompt, choices))

for v in input_variables:
    while True:
        raw_input("""What is the value of %s? Make sure it is in standard
units, however, do not include the unit.""" % v)
        try:
            suvat[v] = float(val)
            print "%s is %s%s" % (v, val, units[v])
            break
        except:
            print "You must enter a number. Don't include units!"

# for readability of the maths, turn dictionary into variables
s, u, v, a, t = [suvat[k] for k in variables]

# (not tested)
if s is None:
    if t is None:
        t = (v - u) / a
    if v is None:
        s = u * t + .5 * a * t * t
    elif a is None:
        s = .5 * (u + v) * t
    else:
        s = v * t - .5 * a * t * t
if v is None:
    if u is None:
        u = s / t - .5 * a * t * t
    if t is None:
        v = math.sqrt(u * u + 2 * a * s)
    else:
        v = 2 * s / t - u
if u is None:
    if a is None:
        a = 2 * v / t - s / (t * t)
    u = math.sqrt(v * v - 2 * a * s)
if a is None:
    a = (v * v - u * u) / (2 * s)
if t is None:
    t = (v - u) / a

# turn the set of variables back into a dictionary
solutions = dict(zip(variables, [s, u, v, a, t]))
print 'Solution: %s=%s%s' % (aim, solutions[aim], units[aim])
Stuart
  • 9,597
  • 1
  • 21
  • 30