DEV Community

Anton Shcherbatov
Anton Shcherbatov

Posted on

Identity and Equality in Python

We assume you already know how to write simple Python programs and understand basic syntax (if, for, functions, lists). Here, we're not discussing how to use the language, but why it works the way it does.

If you ask a beginner what the difference is between is and ==, you'll often hear something like this:

"== compares values, while is compares references."

It's a common explanation.

And while it points in the right direction, it isn't quite accurate.

Let's see what's really happening.

We'll start with a simple example:

a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)
print(a is b)
Enter fullscreen mode Exit fullscreen mode

The output is:

True
False
Enter fullscreen mode Exit fullscreen mode

At first glance, that seems odd.

If the lists are identical, why does one comparison return True while the other returns False?

To answer that, let's recall what we've learned in the previous articles.

In Python, variables don't contain objects.

Names refer to objects.

When we execute:

a = [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

Python creates a list object.

Then we execute:

b = [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

This creates another list object.

Even though both lists contain exactly the same values, they are two distinct objects.

Visually:

a ───► [1, 2, 3]

b ───► [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

Now the behavior of the two operators becomes much easier to understand.

The == operator asks:

Do these objects have the same value?

In this case, they do.

So:

a == b
Enter fullscreen mode Exit fullscreen mode

returns:

True
Enter fullscreen mode Exit fullscreen mode

The is operator asks a completely different question:

Are these the very same object?

This time, the answer is no.

So:

a is b
Enter fullscreen mode Exit fullscreen mode

returns:

False
Enter fullscreen mode Exit fullscreen mode

In other words:

  • == compares an object's value
  • is compares an object's identity

Now consider a different example:

a = [1, 2, 3]
b = a

print(a == b)
print(a is b)
Enter fullscreen mode Exit fullscreen mode

This time, both comparisons return:

True
True
Enter fullscreen mode Exit fullscreen mode

Why?

Because no second list was ever created.

The assignment:

b = a
Enter fullscreen mode Exit fullscreen mode

simply gives the existing object another name.

Now the picture looks like this:

a ─┐
   ├──► [1, 2, 3]
b ─┘
Enter fullscreen mode Exit fullscreen mode

Since both names refer to the same object:

  • the values are equal
  • and the identity is the same

That's why both operators return True.


At this point, you might wonder:

If is only checks whether two names refer to the same object, why do we need it at all?

Why not always use ==?

Most of the time, == is exactly what you want.

Use it whenever you're comparing values - for example, numbers, strings, or lists.

But sometimes the identity of an object matters more than its value.

The best-known example is None.

You've probably seen code like this:

if value is None:
    ...
Enter fullscreen mode Exit fullscreen mode

Notice that it uses is, not ==. Why?

Because there's only one None object in a Python program.

We're not asking whether another object happens to behave like None.

We're asking whether this is the None object.

That's why the Python community recommends writing:

if value is None:
Enter fullscreen mode Exit fullscreen mode

instead of:

if value == None:
Enter fullscreen mode Exit fullscreen mode

It clearly communicates your intent and is considered the idiomatic way to write the comparison.


You may occasionally run into something even more surprising:

a = 10
b = 10

print(a is b)
Enter fullscreen mode Exit fullscreen mode

On many Python implementations, this prints:

True
Enter fullscreen mode Exit fullscreen mode

But based on everything we've discussed so far, you might have expected False.

Don't worry - this doesn't mean numbers behave differently.

Python sometimes reuses certain small immutable objects as an internal optimization.

Small integers are one example.

The important thing is that your code should never rely on this behavior.

If you're comparing values, use ==.

If you're checking whether two names refer to the same object, use is.


We can now summarize the difference with one simple rule.

If you're asking:

"Do these objects have the same value?"

use ==.

If you're asking:

"Are these the same object?"

use is.

That's exactly why the previous articles in this series were so important.

Without understanding objects and names, the difference between is and == feels like an arbitrary rule you have to memorize.

Once you understand Python's object model, though, the distinction becomes completely natural.

Top comments (0)