Skip to main content
added 1381 characters in body
Source Link

The main line that does the execution is here:

print(converters[option](leng1))

It is fetching the value from converters, which is a lamdba (a function you can write as an expression), and then calls it with the value entered by the user.

Here is a simplified example, because this is the main part that did the "shrinking" of your code.

Lets say you have two methods, a and b, and depending on what the user selects, you have to call either a or b. You might write some code like this:

def a():
  return 'Hello'

def b():
  return 'Goodbye'

user_request = input('Please enter either a or b: ')
if user_request == 'a':
   print(a())
if user_request == 'b':
   print(b())

This is fine if its two options, but what if there are 3, 4 or 9 options? Now you'll end up with a large chain of if/else statements. To prevent this, what you can do is use a call map - which is a dictionary that has the values as the method names:

call_map = dict()
call_map['a'] = a
call_map['b'] = b

As methods are just like normal values, you can assign and pass them around. Now what you want to do is call the method that corresponds to the input:

option = 'a'
function_to_call = call_map[option]
result = function_to_call()

You can shorten the above with:

result = call_map[option]()

As the dictionary only has keys for those values that map to valid functions, it is easy to filter out an invalid entry - it simply won't be in the list of keys for that dictionary.

if option not in call_map.keys():
    print('{} is not a valid option'.format(option))
else:
    print('The result is: {}'.format(call_map[option]())

The main line that does the execution is here:

print(converters[option](leng1))

It is fetching the value from converters, which is a lamdba (a function you can write as an expression), and then calls it with the value entered by the user.

Here is a simplified example, because this is the main part that did the "shrinking" of your code.

Lets say you have two methods, a and b, and depending on what the user selects, you have to call either a or b. You might write some code like this:

def a():
  return 'Hello'

def b():
  return 'Goodbye'

user_request = input('Please enter either a or b: ')
if user_request == 'a':
   print(a())
if user_request == 'b':
   print(b())

This is fine if its two options, but what if there are 3, 4 or 9 options? Now you'll end up with a large chain of if/else statements. To prevent this, what you can do is use a call map - which is a dictionary that has the values as the method names:

call_map = dict()
call_map['a'] = a
call_map['b'] = b

As methods are just like normal values, you can assign and pass them around. Now what you want to do is call the method that corresponds to the input:

option = 'a'
function_to_call = call_map[option]
result = function_to_call()

You can shorten the above with:

result = call_map[option]()

As the dictionary only has keys for those values that map to valid functions, it is easy to filter out an invalid entry - it simply won't be in the list of keys for that dictionary.

if option not in call_map.keys():
    print('{} is not a valid option'.format(option))
else:
    print('The result is: {}'.format(call_map[option]())
Source Link

A few things you can do:

  1. Whenever you have to execute a few things after a loop (a conditional branch execution), this is the prime candidate to use a dictionary. In Python, functions are just names of code blocks; so you can use them anywhere you can use any other variable.

  2. You only need to ask for the unit and the amount once after the correct selection has been made.

Here is a version of your code that does this; I have left your comments in place:

metric_length=['km', 'm' , 'cm']
imperial_length=['mi', 'ft', 'in']
menu_type=['Length-1', 'Weight-2', 'Cacpacity-3']
metric_mass=['t','kg', 'g']
imperial_mass=['stone', 'lb', 'oz']

converters = dict()
converters['km'] = lambda x: '{} {}'.format(x/1.6, 'miles')
converters['m'] = lambda x: '{} {}'.format(x*3.26, 'feet')
converters['cm'] = lambda x: '{} {}'.format(x/2.54, 'inches')
converters['mi'] = lambda x: '{} {}'.format(x*1.6, 'kilometers')
converters['ft'] = lambda x: '{} {}'.format(x/3.26, 'meters')
converters['in'] = lambda x: '{} {}'.format(x*2.54, 'centimeters')
converters['t'] = lambda x: '{} {}'.format(x*157.47, 'stone')
converters['kg'] = lambda x: '{} {}'.format(x*2.2, 'pounds')
converters['g'] = lambda x: '{} {}'.format(x*0.035, 'ounces')
converters['stone'] = lambda x: '{} {}'.format(x*0.00635, 'tonnes')
converters['lb'] = lambda x: '{} {}'.format(x*0.4536, 'kilograms')
converters['oz'] = lambda x: '{} {}'.format(x*28.35, 'grams')

print("Welcome to the Conversion-Calculator")
print('\n'.join(menu_type))
measure=int(input("Please select what you would like to convert by typing a number:"))

#starting if statement chain
if measure==1:
 #menu to chose from either metric to imperial or vice-versa
 print("Metric-Imperial - 1")
 print("Imperial-Metric - 2")
 choice=int(input("Choose a conversion by typing a number: "))

 #If 1 is chosen follows by asking what metric distance to convert
 if choice== 1:
     print('\n'.join(metric_length))    
 #This is the code for the second choice in the program
 #If 2 is chosen follows by asking what imperial distance to convert
 if choice== 2:
     print('\n'.join(imperial_length))
     #prints the imperial length menu
     

if measure==2:
 #menu to chose from either metric to imperial or vice-versa
 print("Metric-Imperial - 1\n")
 print("Imperial-Metric - 2\n")
 choice2=int(input("Choose a conversion by typing a number: "))
 #If 1 is chosen follows by asking what metric distance to convert
 if choice2== 1:
     print('\n'.join(metric_mass))
     #prints the metric length menu
 #This is the code for the second choice in the program
 #If 2 is chosen follows by asking what imperial mass to convert
 if choice2== 2:
     print('\n'.join(imperial_mass))

option = input("Please choose the measurement you want to use: ") 
if option not in converters.keys():
    print('Invalid Entry')
else:
    leng1=int(input("Please enter a number to convert: "))
    print(converters[option](leng1))

I also made the method names the same as the inputs, this way if the user enters something invalid, the key in the converters dictionary will not exist - an "cheap" way to get the validation done.