Do You Know How `or` and `and` Work in Python?

3 months ago 2

Let's start with an easy question. Play along, please. I know you know how to use the or keyword, just bear with me for a bit…

Have you answered? If you haven't, please do, even if this is a simple question for you.

…Have you submitted your answer now?

I often ask this question when running live courses, and people are a bit hesitant to answer because it seems to be such a simple, even trivial, question. Most people eventually answer: True.

OK, let's dive further into how or works, and we'll also explore and in this article.

You may not have felt the need to cheat when answering the question above. But you could have just opened your Python REPL and typed in the expression. Let's try it:

All code blocks are available in text format at the end of this article • #1 • The code images used in this article are created using Snappify. [Affiliate link]

Wait. What?!

The output is not True. Why 5? Let's try it again with different operands:

#2

Hmm?!

Support The Python Coding Stack

Let's review the concept of truthiness in Python. Every Python object is either truthy or falsy. When you pass a truthy object to the built-in bool(), you get True. And, you guessed it, you'll get False when you pass a falsy object to bool().

In situations where Python is expecting a True or False, such as after the if or while keywords, Python will use the object's truthiness value if the object isn't a Boolean (True or False).

Let's get back to the expression 5 or 0. The integer 5 is truthy. You can confirm this by running bool(5), which returns True. But 0 is falsy. In fact, 0 is the only falsy integer. Every other integer is truthy. Therefore, 5 or 0 should behave like True. If you write if 5 or 0:, you'll expect Python to execute the block of code after the if statement. And it does.

But you've seen that 5 or 0 evaluates to 5. And 5 is not True. But it's truthy. So, the statement if 5 or 0: becomes if 5:, and since 5 is truthy, this behaves as if it were if True:.

But why does 5 or 0 give you 5?

The or keyword is looking at its two operands, the one before and the one after the or keyword. It only needs one of them to be true (by which I mean truthy) for the whole expression to be true (truthy).

So, what happens when you run the expression 5 or 0? Python looks at the first operand, which is 5. It's truthy, so the or expression simply gives back this value. It doesn't need to bother with the second operand because if the first operand is truthy, the value of the second operand is irrelevant. Recall that or only needs one operand to be truthy. It doesn't matter if only one or both operands are truthy.

So, what happens if the first operand is falsy?

#3

The first of these expressions has one truthy and one falsy operand. But the first operand, 0, is falsy. Therefore, the or expression must look at the second operand. It's truthy. The or expression gives back the second operand. Therefore, the output of the or expression is truthy. Great.

But the or expression doesn't return the second operand because the second operand is truthy. Instead, it returns the second operand because the first operand is falsy.

When the first operand in an or expression is falsy, the result of the or expression is determined solely by the second operand. If the second operand is truthy, then the or expression is truthy. But if the second operand is falsy, the whole or expression is falsy. Recall that the previous two sentences apply to the case when the first operand is falsy.

That's why the second example above, 0 or "", returns the empty string, which is the second operand. An empty string is falsy—try bool("") to confirm this. Any non-empty string is truthy.

So:

  • or always evaluates to the first operand when the first operand is truthy

  • or always evaluates to the second operand when the first operand is falsy

But there's more to this…

Let's get back to the expression 5 or 0. The or looks at the first operand. It decides it's truthy, so its output is this first operand.

It never even looks at the second operand.

Do you want proof? Consider the following or expression:

#4

What's bizarre about this code at first sight? The expression int("hello") is not valid since you can't convert the string "hello" to an integer. Let's confirm this:

#5

But the or expression above, 5 or int("hello"), didn't raise this error. Why?

Because Python never evaluated the second operand. Since the first operand, 5, is truthy, Python decides to be lazy—it doesn't need to bother with the second operand. This is called short-circuit evaluation.

That's why 5 or int("hello") doesn't raise the ValueError you might expect from the second operand.

However, if the first operand is falsy, then Python needs to evaluate the second operand:

#6

In this case, you get the ValueError raised by the second operand.

Lazy is good (some will be pleased to read this). Python is being efficient when it evaluates expressions lazily. It saves time by avoiding the evaluation of expressions it doesn't need!

How about the and keyword? The reasoning you need to use to understand and is similar to the one you used above when reading about or. But the logic is reversed. Let's try this out:

#7

The and keyword requires both operands to be truthy for the whole expression to be true (truthy). In the first example above, 5 and 0, the first operand is truthy. Therefore, and needs to also check the second operand. In fact, if the first operand in an and expression is truthy, the second operand will determine the value of the whole expression.

When the first operand is truthy, and always returns the second operand. In the first example, 5 and 0, the second operand is 0, which is falsy. So, the whole and expression is falsy.

But in the second example, 5 and "hello", the second operand is "hello", which is truthy since it's a non-empty string. Therefore, the whole expression is truthy.

What do you think happens to the second operand when the first operand in an and expression is falsy?

#8

The first operand is falsy. It doesn't matter what the second operand is, since and needs both operands to be truthy to evaluate to a truthy value.

And when the first operand in an and expression is falsy, Python's lazy evaluation kicks in again. The second operand is never evaluated. You have a short-circuit evaluation:

#9

Once again, you use the invalid expression int("hello") as the second operand. This expression would raise an error when Python evaluates it. But, as you can see, the expression 0 and int("hello") never raises this error since it never evaluates the second operand.

Let's summarise how and works:

  • and always evaluates to the first operand when the first operand is falsy

  • and always evaluates to the second operand when the first operand is truthy

Compare this to the bullet point summary for the or expression earlier in this article.

Do you want to try video courses designed and delivered in the same style as these posts? You can get a free trial at The Python Coding Place and you also get access to a members-only forum.

Try Out The Python Coding Place

Here's code you may see that uses the or expression’s short-circuiting behaviour:

#10

Now, you're assigning the value of the or expression to a variable name, person. So, what will person hold?

Let's try this out in two scenarios:

#11

In the first example, you type your name when prompted. Or you can type my name, whatever you want! Therefore, the call to input() returns a non-empty string, which is truthy. The or expression evaluates to this first operand, which is the return value of the input() call. So, person is the string returned by input().

However, in the second example, you simply hit enter when prompted to type in a name. You leave the name field blank. In this case, input() returns the empty string, "". And an empty string is falsy. Therefore, or evaluates to the second operand, which is the string "Unknown". This string is assigned to person.

So, or and and don't always evaluate to a Boolean. They'll evaluate to one of their two operands, which can be any object—any data type. Since all objects in Python are either truthy or falsy, it doesn't matter that or and and don't return Booleans!

Now you know!

Do you want to join a forum to discuss Python further with other Pythonistas? Upgrade to a paid subscription here on The Python Coding Stack to get exclusive access to The Python Coding Place's members' forum. More Python. More discussions. More fun.

And you'll also be supporting this publication. I put plenty of time and effort into crafting each article. Your support will help me keep this content coming regularly and, importantly, will help keep it free for everyone.

Image by Paolo Trabattoni from Pixabay

Code in this article uses Python 3.13

The code images used in this article are created using Snappify. [Affiliate link]

You can also support this publication by making a one-off contribution of any amount you wish.

Support The Python Coding Stack

For more Python resources, you can also visit Real Python—you may even stumble on one of my own articles or courses there!

Also, are you interested in technical writing? You’d like to make your own writing more narrative, more engaging, more memorable? Have a look at Breaking the Rules.

And you can find out more about me at stephengruppetta.com

Further reading related to this article’s topic:

Code Block #1
5 or 0 # 5
Code Block #2
"hello" or [] # 'hello'
Code Block #3
0 or 5 # 5 0 or "" # ''
Code Block #4
5 or int("hello") # 5
Code Block #5
int("hello") # Traceback (most recent call last): # File "<input>", line 1, in <module> # ValueError: invalid literal for int() with base 10: 'hello'
Code Block #6
0 or int("hello") # Traceback (most recent call last): # File "<input>", line 1, in <module> # ValueError: invalid literal for int() with base 10: 'hello'
Code Block #7
5 and 0 # 0 5 and "hello" # 'hello'
Code Block #8
0 and 5 # 0
Code Block #9
0 and int("hello") # 0
Code Block #10
person = input("Enter name: ") or "Unknown"
Code Block #11
person = input("Enter name: ") or "Unknown" # Enter name: >? Stephen person # 'Stephen' person = input("Enter name: ") or "Unknown" # Enter name: >? person # 'Unknown'

For more Python resources, you can also visit Real Python—you may even stumble on one of my own articles or courses there!

Also, are you interested in technical writing? You’d like to make your own writing more narrative, more engaging, more memorable? Have a look at Breaking the Rules.

And you can find out more about me at stephengruppetta.com

Read Entire Article