Ex36, how does "or" work with "in"?

Hi! I’m building a game as part of exercise 36 for LPTHW. I had a quick question about how “in” works with operators in if/elif/else chains.

I’m going to post all of my code below, but I’m mainly interested in one bit which I’ll highlight below.

backflip = False

def sword_room():
    print('You enter a small cavernous room.')
    print('In the middle of the room lies a circular fountain, made of limestone.')
    print("It's two levels tall, made up of two concentric circles.")
    print('As your eyes rise to the top, you notice water seems to be flowing from a sword placed in the center.')
    print('The sword has a key at its hilt. You notice a door at the other side of the room.')
    print('What do you do?')

    has_rock = False


    while True:
        sword_room_choice = input("> ")

        if "key" and "get" in sword_room_choice:
            die("As you walk near the fountain, it starts to erupt into an enormous geyser, filling the room with water and drowning you.")
        elif "sword" and "get" in sword_room_choice:
            die("As you walk near the fountain, it starts to erupt into an enormous geyser, filling the room with water and drowning you.")
        elif "look around" in sword_room_choice:
            print("You notice a rock near your feet.")
        elif "throw" in sword_room_choice and has_rock == True:
            print("You throw the rock at the sword.")
            die("You hit it! As you do, the fountain starts to erupt into an enormous geyser, filling the room with water and drowning you.")
        elif "pick up" in sword_room_choice:
            print("You pick up the rock.")
            has_rock = True
        elif "door" in sword_room_choice:
            print("You walk up to the door.")
            print("Do you want to open it? (Y/N)")

            door_choice = input("> ")

            if "y" in door_choice:
                print("Are you sure?")

                door_choice_2 = input("> ")

                if "y" in door_choice_2:
                    print("You touch the door handle, cautiously.")
                    print("It's unlocked. You walk through it.")
                    end_room()
                else:
                    print("You walk away from the door.")

            else:
                print("You walk away from the door.")
                print("What do you do?")
        else:
            print("I got no idea what that means.")


def die(why):

    print(why, "Nice job.")
    print("Would you like to play again? Y/N")

    play_again = input("> ")

    if "nay" in play_again:
        exit(0)
    elif "y" in play_again:
        sword_room()
    else:
        exit(0)

    return backflip == False #return cuts off a function

sword_room()

One of my elif conditions is supposed to let you pick up a rock, essentially, and I wanted the program to be able to understand “pick up” and “take” as the same thing, and run the same response.

So I changed this:

elif "pick up" in sword_room_choice:
            print("You pick up the rock.")
            has_rock = True

to this:

elif "pick up" or "take" in sword_room_choice:
            print("You pick up the rock.")
            has_rock = True

But when I make that change, everything that’s not explicitly defined before that elif block immediately went to that branch instead of its proper branch.

my terminal output, for example:

Devin’s MacBook Air:python_hard_way Devin$ python3.6 sword_room.py
You enter a small cavernous room.
In the middle of the room lies a circular fountain, made of limestone.
It’s two levels tall, made up of two concentric circles.
As your eyes rise to the top, you notice water seems to be flowing from a sword placed in the center.
The sword has a key at its hilt. You notice a door at the other side of the room.
What do you do?

open
You pick up the rock.
randomwords
You pick up the rock.
look around
You notice a rock near your feet.
ggggggg
You pick up the rock.

I fixed the problem like so:

elif "pick up" in sword_room_choice or "take" in sword_room_choice:
            print("You pick up the rock.")
            has_rock = True

But why didn’t my original code work? Can Python just not understand what “or” does before “in” and always reads it as True? What’s going on there?

Python interprets that test like so

("pick up") or ("take" in sword_room_choice)

where the first part is a non-empty string so it is considered true, and so this test always succeeds, effectively blocking every branch below.

In other words, the in operator has a higher precedence than the or operator. Yet in other words, you can’t combine or and in the way you thought you could.

2 Likes

Yes computers are dumb and you need to be explicit with the if statement.

If you want to come up with a selection of words that do the same actions, you could create a list of them and use that instead:

acceptable_words = [“take”, “pickup”, “acquire”]

if userinput in acceptable_words: 
   ....
3 Likes

Yes, or if you can’t match exactly:

if any(word in user_input for word in acceptable_words)
2 Likes

Awesome. Thank you so much, guys.