What's wrong with my if-else statements in Python 3?

  • #1
Goal:
I'm trying to allow the user to input varying spellings for certain auto services, and still have my code work properly. My goal was to use the if-else statements to ensure that if the user misspelled a service, the code could correct the error by changing the variable assignment to the string that matched my dictionary key.
The issue:
The code will output: Tire rotation for any input that I enter for auto_serv. Where have I made a mistake? Any better ideas to program this? Keep in mind, I'm a first time programmer that's doing this for class, and I just learned if-else statements.
The code:
Python:
# dictionary assigns the cost for each service
services = {'Oil change': 35,
            'Tire rotation': 19,
            'Car wash': 7,
            'Car wax': 12}
# auto_serv is the user's desired car service
auto_serv = input('Desired auto service:')
# The following four 'if' statements are to allow the user multiple variances in spelling of desired auto service
if auto_serv == 'Tirerotation' or 'tirerotation':
    auto_serv = 'Tire rotation'

elif auto_serv == 'Oilchange' or 'oilchange':
    auto_serv = 'Oil change'

elif auto_serv == 'Carwash' or 'carwash':
    auto_serv = 'Car wash'

elif auto_serv == 'Carwax' or 'carwax':
    auto_serv = 'Car wax'

# the if-else statements are to give a result for each service the user requests
if auto_serv == 'Tire rotation':
    print('You entered:', auto_serv)
    print('Cost of %s: $%d' % (auto_serv, services[auto_serv]))

elif auto_serv == 'Oil change':
    print('You entered:', auto_serv)
    print('Cost of %s: $%d' % (auto_serv, services[auto_serv]))

# ...there are more elif statements that follow this code with the other auto services
 

Answers and Replies

  • #2
12,501
6,290
One thing you can do is convert the input to either all lowercase or all uppercase, strip the input to remove spaces at the from or back and change your if expressions accordingly. Next you can drop the first if/elif group as they just map the input to an acceptable string.
 
  • #3
Your if/elif statements need to be changed to, for example:

if auto_serv == 'Tirerotation' or auto_serv == 'tirerotation':
 
  • Like
Likes Yelzobj, astroman707, Mark44 and 2 others
  • #4
hmmm27
Gold Member
625
274
tldr; wot she said ^

I'm not a Python programmer but, given the output and assuming no warnings popped up, it looks like your current code is telling the compiler to do a bit-logic operation on the two strings, which is way above your pay grade as a "first time programmer".

As far as "could it be better?" is concerned, sure, but - more importantly - does it incorporate everything you've learned up to this point in the course, plus what you could reasonably be expected to investigate on your own.
 
  • #5
phinds
Science Advisor
Insights Author
Gold Member
16,737
7,421
To say what the others have said, but in different words,

if auto_serv == 'Tirerotation' or 'tirerotation':

Translates, depending on the language, to:

1) if (auto_serv == "Tirerotation') or (if "tirerotation' evaluates to a Boolean experssion which is true) then

2) if (auto_serv == "Tirerotation') evaluates to all 0's or all 1's and then LOGICALLY OR'ed with the binary values of 'tirerotation'

CLEARLY #2 is not even remotely what you want and #1 is just what happens when, as Sarah pointed out, you omit the conditional on the second part.
 
  • #6
Ibix
Science Advisor
Insights Author
2020 Award
7,396
6,482
The correction made by @Sarah Hrmbree is correct. The subsequent explanations for why your code does what it does are not, unless python 3 has completely changed handling of if and or since 2.7 (and I couldn't find any docs saying it has done). The or operator is not a bitwise operator in python; it's strictly a boolean comparison. The bitwise-or operator is | in python.

What is happening is that your line
Python:
if auto_serv == 'Tirerotation' or 'tirerotation':
means if auto_serv=='Tirerotation' is true, or if 'tirerotation' is true, then do whatever. The problem is what python does when you ask if a string is true. Any non-empty string is treated as true, and only an empty string is false. Since 'tirerotation' is not an empty string the condition is always true and the first branch always executes. All of the other elif conditions also evaluate to true for the same reason, but since the first branch executed the code doesn't consider any other.

There are many ways to improve this code. In terms of incremental improvements, I would look up python's in operator as well as considering converting to lower or upper case as @jedishrfu recommends.
 
  • Like
Likes m4r35n357 and jedishrfu
  • #7
Ibix
Science Advisor
Insights Author
2020 Award
7,396
6,482
...and one more thing, @astroman707. In your second if/elif tree, have you noticed how every branch is identical? Why are you bothering making a decision if you are going to do the same thing whatever the result of the decision?

And after you've fixed that you could look at whether you could use a similar approach to remove your first if/elif tree.
 
Last edited:
  • Like
Likes m4r35n357
  • #9
Your if/elif statements need to be changed to, for example:

if auto_serv == 'Tirerotation' or auto_serv == 'tirerotation':
Thank you! That was the error staring me right in the face!
 
  • Like
Likes jedishrfu
  • #10
Thanks everyone for your inputs! Some of your suggestions are a bit too advanced for me, but still all interesting and helpful. Thanks!
 
  • Like
Likes jedishrfu
  • #11
cronxeh
Gold Member
961
10
[Moderator's note: off topic content deleted.]

The right approach is to use a jaccard index to match input similarity to the list of keywords you have in your services, and return the highest matching value.
 
Last edited by a moderator:
  • #12
cronxeh
Gold Member
961
10
Python:
def jaccard(a, b):
    union = list(set(a+b))
    intersection = list(set(a) - (set(a) - set(b)))
    return float(len(intersection))/len(union)

# dictionary assigns the cost for each service
services = {'Oil change': 35,
            'Tire rotation': 19,
            'Car wash': 7,
            'Car wax': 12}
user_input = input('Desired auto service:')
matching_service = sorted([(service, jaccard(user_input, service)) for service in services.keys()], key=lambda x:x[1], reverse=True)[0][0]
print("Best matching service:", matching_service, "and cost:", services.get(matching_service))
 
Last edited:
  • #13
34,687
6,393
[Moderator's note: Off topic content deleted.]

The right approach is to use a jaccard index to match input similarity to the list of keywords you have in your services, and return the highest matching value.
Based on the OP's statement that some of what was already said is above his current knowledge, your approach with lists and sets is probably waaaay beyond his level of expertise.
 
Last edited by a moderator:
  • #14
cronxeh
Gold Member
961
10
One of his requirements was to "still have my code work properly." With his current approach it would not scale as more services are added to the dictionary, or if it is refactored to pull from a database.

[Moderator's note: Off topic content deleted.]
 
Last edited by a moderator:
  • #15
PeterDonis
Mentor
Insights Author
2020 Award
32,942
11,432
Your if/elif statements need to be changed to, for example:

if auto_serv == 'Tirerotation' or auto_serv == 'tirerotation':
A way to spell this that works better as more alternatives pile up is:

if auto_serv in ('Tirerotation', 'tirerotation'):
 
  • #16
PeterDonis
Mentor
Insights Author
2020 Award
32,942
11,432
I'm trying to allow the user to input varying spellings for certain auto services, and still have my code work properly. My goal was to use the if-else statements to ensure that if the user misspelled a service, the code could correct the error by changing the variable assignment to the string that matched my dictionary key.
Some good pointers have been given for how to do this better; but you might also consider the suggestion @jedishrfu made, which, in more general contexts, goes by the name of "canonicalization": instead of trying to explicitly list all the ways users might incorrectly capitalize or misspell words, apply a function to each user input that forces it into a standard form (such as all lower case, all upper case, Capitalized First Letters Of Each Word, or whatever), and then just test for the standard form. Python's string objects have a rich set of methods for doing this; the most general is probably the "translate" method.
 
  • #17
PeterDonis
Mentor
Insights Author
2020 Award
32,942
11,432
The right approach is to use a jaccard index to match input similarity to the list of keywords you have in your services, and return the highest matching value.
This approach is probably too much for the OP given his stated experience with Python. However, it's worth pointing out that if you do this, you will end up with a matching service even if the user types in word salad. So with this approach it's a good idea to confirm with the user that your code picked the correct matching service, before doing anything else with it.
 
  • #18
PeterDonis
Mentor
Insights Author
2020 Award
32,942
11,432
I would ditch all those IF's and use a switch case statement instead
There is no switch case statement in Python; what your link is describing is how to implement functionality that mimics what that statement does in other languages.

Doing a dictionary lookup (including having functions as values in the dictionary) instead of multiple if/else clauses, which is what the link describes, is indeed a very useful technique in Python; I use it all the time. But it only helps with part of problem the OP is trying to solve, since it still requires an exact match in the dictionary, which means you would have to have an explicit entry for each possible misspelling of each service.
 
Last edited:
  • #19
PeterDonis
Mentor
Insights Author
2020 Award
32,942
11,432
Moderator's note: Off topic posts and content about switch statements has been deleted. Please keep discussion focused on the OP's specific problem.
 

Related Threads on What's wrong with my if-else statements in Python 3?

Replies
9
Views
1K
Replies
6
Views
21K
Replies
6
Views
4K
Replies
2
Views
9K
  • Last Post
Replies
2
Views
593
Replies
4
Views
13K
  • Last Post
Replies
9
Views
17K
  • Last Post
Replies
4
Views
2K
Replies
11
Views
4K
Top