Equality vs Identity

Watch First:


Transcript

You're probably already familiar with equality: that's the == operator. identity uses the is operator.

Equality

Let's say we have two variables, x and y pointing to two lists:

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]

If we say x == y we're asking about equality:

>>> x == y
True

Equality is about whether these two objects represent the same value, whether they're essentially the same thing.

The == operator delegates to one of these objects and asks it, "do you represent the same value as the other object?" That's up to the actual objects to answer.

Identity

The is operator asks about identity.

>>> x is y
False

Unlike ==, the is operator doesn't even look at the objects that x and y point to. Instead, is asks if the variables x and y are pointing to the same object.

The is operator answers the question do two object references actually point to the same object? The expression x is y checks the memory location that x and y are pointing to (by their id) and checks to see if those locations are the same.

>>> id(x)
139957046343296
>>> id(y)
139957046343488

If x and y have the same id in memory, that means we're referencing the same object in two places: x and y are actually referring to the same exact object.

In Python, assignment points a variable to an object.

If we assign x to y:

>>> x = y

We're now pointing the variable x to the same object that y is currently pointing to.

>>> id(x)
139957046343488
>>> id(y)
139957046343488

If we call the append method on the list that x points to

x.append(4)

We've mutated that list object, but we've also mutated the object that y points to because both x and y point to exactly the same object.

>>> x
[1, 2, 3, 4]
>>> y
[1, 2, 3, 4]

These two objects are equal:

>>> x == y
True

But they're also identical (which means they point to the same object):

>>> x is y
True

Inequality and Non-identity

Just as we have equality (==) and inequality (!=):

>>> x == y
True
>>> x != y
False

we also have is for identity (is) and unidentity (is not)... or is it inidentity. How about non-identity.

>>> x is y
True
>>> x is not y
False

The is not operator is one of the few operators in Python that actually has a space inside it.

When is identity used?

You really don't see identity used very often. This is really the most important takeaway about identity and equality: you'll use == all the time, but you'll almost never use is. When comparing two objects, you'll almost always want to check for equality instead of identity.

The place you'll most commonly see is usedis with None:

>>> x is None
False
>>> x is not None
True

, there are other places you might see it used, the one place you'll most commonly see it used

There's only one None value in memory in Python. We're asking the question "is x pointing to the one and only None value".

You'll only see is used with special values where there's only one of them in memory. I call these sentinel values. Sentinel objects are considered completely unique. There's only one of them floating in the memory.

Sentinel values are pretty much the one place you'll see identity used and None is by far the most common sentinel value in Python.

PEP 8, the Python style guide, says you should use identity to compare with None. So you should never x == None, but instead type x is None. That's the convention that we use with None in Python.

Summary

When you want to ask the question "does one object represent the same data as another object", you pretty much always want to use equality (with the == or != operators).

You'll almost never need to ask the question "is one pointer referencing literally the same object as another pointer". If you do want to ask that question though, you'll check identity (with the is and is not operators).

The one time that you really should rely on identity is when comparing to None (checking x is None).