Do You Really Know How `or` And `and` Work in Python?
Let's explore the Python expression `5 or 0`
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.
or
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:

Wait. What?!
The output is not True
. Why 5
? Let's try it again with different operands:
Hmm?!
Truthy and Falsy
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
).
Back to or
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
?
or
Only Needs One Truthy Value
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?
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 truthyor
always evaluates to the second operand when the first operand is falsy
But there's more to this…
Lazy Evaluation • Short Circuiting
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:
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:
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:
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!
and
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:
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?
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:
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 falsyand
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.
More on Short-Circuiting
Here's code you may see that uses the or
expression’s short-circuiting behaviour:
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:
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
.
Final Words
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.
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:
Appendix: Code Blocks
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
That not all coders may fully understand how these work is why I'm leery of using them to control execution in my code. For instance, I'd use the input function alone and then look at its return value. Chances are I'd want to do more to vet the input anyway.