1

I'm trying to write a code in Python three that converts temperatures and distances from one unit to another. I'm told that I need to use functions and that the user will input either F (Fahrenheit), C (Celsius), or K (Kelvin) and the temperature will be converted from whatever they choose to F, C or K. So I wrote a function for each scenario. A function for if it's converted from F, another if it's converted from C, and another if it's converted from K. I also did this for inches, feet, yards, and miles.

So after I wrote all of the functions I wrote an if, elif, and else statement which I want to call each function depending on what the user types. So if the user inputs "F" I want it to call the convert_from_F() function, or if they put "K" I want it to use the convert_from_K(), or if the user types "inch" I want it to use the convert_from_inch() function. I thought that the way to do this would be to use the if, elif, and else statement. However, no matter what I type I'm always given the error message:

NameError: name 'F' is not defined

I would have thought that the iterations would continue past each statement if it found that the user didn't input that particular instruction. It also doesn't work if I (as the user) put 'F.' I'm not sure how to fix this code. What am I missing from it?

Also, I'm using an online python 3 compiler to write my program: OnlineGDB

def convert_from_F():
   F = float(input("Please input the temperature in F: "))
   print("Temperature in F is", F)
   print("Temperature in C is", (F-32)*5/9)
   print("Temperature in K is", (F-32)*5/9 + 273.15)

def convert_from_C():
   C = float(input("Please input the temperature in C: "))
   print("Temperature in F is", (C*9/5) + 32)
   print("Temperature in C is", C)
   print("Temperature in K is", C+273.15)

def convert_from_K():
   K = float(input("Please input the temperature in K: "))
   print("Temperature in F is", (K-273.15)*9/5 + 32)
   print("Temperature in C is", K-273.15)
   print("Temperature in K is", K)

def convert_from_inch():
   inch = float(input("Please input the distance in inches: "))
   print("Distance in inches is:", inch)
   print("Distance in feet is:", inch/12)
   print("Distance in yards is:", inch/36)
   print("Distance in miles is:", inch/63360)

def convert_from_ft():
   ft = float(input("Please input the distance in feet: "))
   print("Distance in inches is:", ft*12)
   print("Distance in feet is:", ft)
   print("Distance in yards is:", ft/3)
   print("Distance in miles is:", ft/5280)

def convert_from_yd():
   yd = float(input("Please input the distance in yards: "))
   print("Distance in inches is:", yd*36)
   print("Distance in feet is:", yd*3)
   print("Distance in yards is:", yd)
   print("Distance in miles is:", yd*1760)

def convert_from_mi():
   mi = float(input("Please input the distance in miles: "))
   print("Distance in inches is:", mi*63360)
   print("Distance in feet is:", mi*5280)
   print("Distance in yards is:", mi*1760)
   print("Distance in miles is:", mi)

print("To convert distance input inch, ft, yd, or mi. To convert \ 
temperatures please input F, C, or K. ")
user_input = input("Your input: ")

def user_conversion():
   if user_input == F or f:
       convert_from_F()
   elif user_input == C or c:
       convert_from_C()
   elif user_input == K or k:
       convert_from_K()
   elif user_input == inch:
       convert_from_inch()
   elif user_input == ft:
       convert_from_ft
   elif user_input == yd:
       convert_from_yd()
   elif user_input == mi:
       convert_from_mi()
   else:
       print("Invalid input.")

print(user_conversion())

Edit: I saw that this was marked as a possible duplicate. The duplicate question doesn't help me, I wasn't trying to make this into a set, I was trying to figure out how I could make an if statement run. The solutions given for my problem aren't like the ones for the other question. However, I'm new to Python so it's entirely possible that I can't make the connections that more experienced people can make. The answers I received here did help me.

matryoshka
  • 135
  • 8
  • You need to quote your strings, i.e. `if user_input == "F" or user_input == "f"`, or a shorter version: `if user_input.lower() == "f":`... – zwer Jul 24 '18 at 21:14
  • 1
    @zwer `str.casefold` is preferable because it handles other languages better. – wizzwizz4 Jul 24 '18 at 21:15
  • Possible duplicate of [How to test multiple variables against a value?](https://stackoverflow.com/questions/15112125/how-to-test-multiple-variables-against-a-value) – tripleee Jul 24 '18 at 21:16
  • @tripleee I disagree, and I edited the post to reflect that. – matryoshka Jul 24 '18 at 21:30
  • A note for better code - make all your magic numbers into constants at the module level (e.g. `FEET_PER_YARD = 3`... also/or maybe make functions that perform the individual conversions. – Jonathan Allan Jul 24 '18 at 21:55
  • `yd*1760` should be `yd/1760` – Jonathan Allan Jul 24 '18 at 22:11
  • FWIW [here](https://repl.it/@jjallan/MetricConverter) is a different approach which has one `distance_conversion` function and one `temperature_conversion` one - both convert to an intermediate unit. The code has constants for the units, their short names, and parts of the conversions (the magic numbers). It also only has a single `print` statement for the conversion results and does not show the unconverted result. – Jonathan Allan Jul 24 '18 at 23:43

6 Answers6

2

Your if construct is wrong. It has to be if user_input == 'F' or user_input == 'f':

Alternatively you can write it shortly as

if user_input in ['F', 'f']:

Or as specified in the comment as

if user_input.lower() == 'f':
Sunitha
  • 11,777
  • 2
  • 20
  • 23
  • It's worth noting that a popular way to do this is `if user_input.lower() == 'f'`. And, if you're gonna use `in` to test for membership, you should use a set, not a list – MoxieBall Jul 24 '18 at 21:13
  • If you want short then `in'fF'` – Jonathan Allan Jul 24 '18 at 21:15
  • Of course! Because it's a string. So I fixed it and now that works, but if I write K it just does the first if statement and quits. I want it to skip the first two and go to the elif statement: elif user_input == 'K' or 'k'. Why would that be? – matryoshka Jul 24 '18 at 21:16
1

It's reading F etc. as variable names. To fix this:

  1. Rewrite them as "F" etc.
  2. Fix your comparisons; or is used for multiple comparisons and can't be used how you're using it. Consider using user_input.casefold() == "f" instead.
wizzwizz4
  • 6,140
  • 2
  • 26
  • 62
0

You need to quote the value and to fix the test, so

   if user_input == F or f:

become

   if user_input == "F" or user_input == "f":

same for other lines

Baptiste Mille-Mathias
  • 2,144
  • 4
  • 31
  • 37
0

You have to have the condition on both sides of the or. So:

def user_conversion():
   if user_input == 'F' or user_input == 'f':
       convert_from_F()
...

or you could just use

def user_conversion():
   if user_input.lower() == 'f':
       convert_from_F()
...
Torin M.
  • 523
  • 1
  • 7
  • 26
0

You want to make sure you're comparing to a string. So, your if-statement would look like:

if user_input == "F" or user_input == "f":
    convert_from_F(user_input)

However, this is somewhat verbose. Instead, try:

if user_input.lower() == "f":
    convert_from_F(user_input)

This version converts the value of user_input to its lowercase variant, or leaves it alone if it's already lowercase. You could do something similar by saving user_input.upper() == "F" too.

Woody1193
  • 7,252
  • 5
  • 40
  • 90
0

A shorter and simpler version could be

if user_input in ["F","f"]:

And so on for the other conditions too.

Reason you are getting that error because the symantics of if statement works onuser boolean True or False.

Let us assume the condition on left hand side (LHS) of 'or' and right hand side (RHS) of it to be boolean.

So in your syntax, LHS is user_input == "F" that returns True or False. But RHS of or is "f". And here is where problem arise. RHS is not symatically correct.

Manish Sharma
  • 173
  • 10
  • A list? Overkill much? You could use a `tuple`, which can be stored as a constant for faster code... or just use a string as these are single-character options. Or, you could use a `set` for faster comparisons, if you don't mind the overhead of a list with the slowness of hashing for just two items (but it's preferable if you've got a lot of things). Btw, LHS and RHS sort of mean something important in C so it's probably best not to use those words. – wizzwizz4 Jul 24 '18 at 21:33