How do I create a list that contain all my conditions without ending with a long if elif stament in Python?

Question:

I am new to coding with Python, (only a few days), and I have encountered many issues already, However, one seems to be persistent. Every time I create a condition I end up with a long list of if-else statements. I searched the website but could not figure out how to find a solution to my specific issue.

I am building a simple unit converter. The code is below:

def get_unit1():
      while True:
          unit1 = input("Which unit would you like to convert from?: ")
          if unit1 == 'km':                                              
              return unit1
          elif unit1 == 'hm':
              return unit1
          elif unit1 == 'da':
              return unit1
          elif unit1 == 'm':
              return unit1
          elif unit1 == 'dm':
              return unit1
          elif unit1 == 'cm':
              return unit1
          elif unit1 == 'mm':
              return unit1
          elif unit1 == 'ml':
              return unit1
          elif unit1 == 'yd':
              return unit1
          elif unit1 == 'ft':
              return unit1
          elif unit1 == 'in':
              return unit1    
          else:
              print("Wrong input, try again.")

  def get_unit2():
      while True:
          unit2 = input("Which unit would you like to convert to?: ")
          if unit2 == 'km':                                              
              return unit2
          elif unit2 == 'hm':
              return unit2
          elif unit2 == 'da':
              return unit2
          elif unit2 == 'm':
              return unit2
          elif unit2 == 'dm':
              return unit2
          elif unit2 == 'cm':
              return unit2
          elif unit2 == 'mm':
              return unit2
          elif unit2 == 'ml':
              return unit2
          elif unit2 == 'yd':
              return unit2
          elif unit2 == 'ft':
              return unit2
          elif unit2 == 'in':
              return unit2    
          else:
              print("Wrong input, try again.")

The condition is working perfectly fine, it’s just that it is long.
When I shrink the condition using OR operator for example:

if unit1 == 'km'or'hm'or'da'or'm'or'dm'or'cm'or'mm'or'ml'or'yd'or'ft'or'in':
                return unit1  

It does work too but when I put the wrong input it accepts it and later the program crashes.

I tried using a list but ended up creating a long code of "if x in list" statements.

Thanks in advance!

Asked By: Strider

||

Answers:

Use in to test if something is in a list.

UNITS = ['km', 'hm', 'da', 'm', 'dm', 'cm', 'mm', 'ml', 'yd', 'ft', 'in']

def get_unit(prompt: str) -> str:
    while True:
        unit = input(prompt)
        if unit in UNITS:
            return unit
        print("Wrong input, try again.")

def get_unit1() -> str:
    return get_unit("Which unit would you like to convert from?: ")

def get_unit2() -> str:
    return get_unit("Which unit would you like to convert to?: ")

A common way to handle the situation where you want input to be one of a specific set of values is to create an Enum that enumerates all the values. You can construct an Enum by giving it one of the values, and it’ll automatically raise ValueError if the value is invalid, only constructing an instance of that Enum if the value is one of the ones you listed. In this example that might look like this:

from enum import Enum

class Unit(Enum):
    KILOMETER = 'km'
    HECTOMETER = 'hm'
    DALTON = 'da'
    METER = 'm'
    DECIMETER = 'dm'
    CENTIMETER = 'cm'
    MILLIMETER = 'mm'
    MILE = 'ml'
    YARD = 'yd'
    FOOT = 'ft'
    INCH = 'in'

def get_unit(prompt: str) -> Unit:
    while True:
        try:
            return Unit(input(prompt))
        except ValueError:
            print("Wrong input, try again.")

def get_unit1() -> Unit:
    return get_unit("Which unit would you like to convert from?: ")

def get_unit2() -> Unit:
    return get_unit("Which unit would you like to convert to?: ")

Having the strings as members of an enum makes it harder to accidentally type them wrong in a different part of the code and create a hard-to-debug problem. This is important because you’ll probably need to reference these values in other places, e.g. in creating a conversion table:

METERS_PER_UNIT = {
    Unit.KILOMETER: 1000,
    Unit.HECTOMETER: 100,
    Unit.METER: 1,
    # ... etc
}

so that you can do:

unit1 = get_unit1()
unit2 = get_unit2()
unit2_per_unit1 = METERS_PER_UNIT[unit1] / METERS_PER_UNIT[unit2]
print(f"1 {unit1.name} is the same as {unit2_per_unit1} {unit2.name}")
Answered By: Samwise