34

I want to check if a variable has one of multiple values. I'm confused about why or doesn't work in this situation. I was following a tutorial that gave the example if (a or b):, but when I try to do this it only checks the variable against the first value. What is wrong with my check?

name = raw_input('Please type in your name:')

if len(name) < 5:
    print "Your name has fewer than 5 characters"
elif len(name) == 5:
    print "Your name has exactly 5 characters"
    if name == ("Jesse" or "jesse"):
        print "Hey Jesse!"
else:
    print "Your name has greater than 5 characters"
davidism
  • 121,510
  • 29
  • 395
  • 339
Leon Gaban
  • 36,509
  • 115
  • 332
  • 529

4 Answers4

52
("Jesse" or "jesse")

The above expression tests whether or not "Jesse" evaluates to True. If it does, then the expression will return it; otherwise, it will return "jesse". The expression is equivalent to writing:

"Jesse" if "Jesse" else "jesse"

Because "Jesse" is a non-empty string though, it will always evaluate to True and thus be returned:

>>> bool("Jesse")  # Non-empty strings evaluate to True in Python
True
>>> bool("")  # Empty strings evaluate to False
False
>>>
>>> ("Jesse" or "jesse")
'Jesse'
>>> ("" or "jesse")
'jesse'
>>>

This means that the expression:

name == ("Jesse" or "jesse")

is basically equivalent to writing this:

name == "Jesse"

In order to fix your problem, you can use the in operator:

# Test whether the value of name can be found in the tuple ("Jesse", "jesse")
if name in ("Jesse", "jesse"):

Or, you can lowercase the value of name with str.lower and then compare it to "jesse" directly:

# This will also handle inputs such as "JeSSe", "jESSE", "JESSE", etc.
if name.lower() == "jesse":
  • 1
    @iCodez : You should add that doing `.lower()` would also cover strings like `'JeSsE'`. – Sukrit Kalra Aug 13 '13 at 15:10
  • `name in {"Jesse", "jesse"}` must be a Python 3 thing, as this appears to be a syntax error in Python 2. – cdhowie Aug 13 '13 at 15:17
  • 1
    @cdhowie - That code worked in Python 2.7 and Python 3.2. Basically, it is creating a set containing "Jesse" and "jesse". Sets run faster with `in` comparisons. I don't know how it works though with Python releases prior to 2.7. –  Aug 13 '13 at 15:19
  • 2
    @iCodez : Tuples are faster if the elements to be checked are only 2 in number. – Sukrit Kalra Aug 13 '13 at 15:23
  • @iCodez Ah, I see. I think the equivalent Python < 2.7 code would be `set(("Jesse", "jesse"))`. – cdhowie Aug 13 '13 at 15:23
  • 1
    @SukritKalra - Yea, I suppose on this small of a scale, the differences are kinda nil. It's just a force of habit. :) I'll update my post. –  Aug 13 '13 at 15:25
  • Just do a timeit result, tuples are almost twice as fast. Though it does not really matter. – Sukrit Kalra Aug 13 '13 at 15:26
  • `"Jesse"` does not _evaluate to True_. It evaluates to the string "Jesse", which is truthy. – khelwood Sep 13 '20 at 23:37
10
if name in ("Jesse", "jesse"):

would be the correct way to do it.

Although, if you want to use or, the statement would be

if name == 'Jesse' or name == 'jesse':

>>> ("Jesse" or "jesse")
'Jesse'

evaluates to 'Jesse', so you're essentially not testing for 'jesse' when you do if name == ("Jesse" or "jesse"), since it only tests for equality to 'Jesse' and does not test for 'jesse', as you observed.

Sukrit Kalra
  • 33,167
  • 7
  • 69
  • 71
  • Ah thanks now I understand :) this works, though will go with iCodez for my specific situation, thanks for taking the time to answer! – Leon Gaban Aug 13 '13 at 15:07
6

If you want case-insensitive comparison, use lower or upper:

if name.lower() == "jesse":
falsetru
  • 357,413
  • 63
  • 732
  • 636
6

The or operator returns the first operand if it is true, otherwise the second operand. So in your case your test is equivalent to if name == "Jesse".

The correct application of or would be:

if (name == "Jesse") or (name == "jesse"):
cdhowie
  • 158,093
  • 24
  • 286
  • 300