Python Difference between is and == Operator

The python identity operator is is quite frequently used to compare objects in python and often in places where the equality operator == should be used. In fact, you should almost always avoid using is when comparing values. In this tutorial, we’d be covering the differences between the two operators and when to use them.

Before discussing their differences, let’s see an example:

a = 50
b = 50

print("Identity: ", a is b)
print("Equality: ", a == b)

What you think should the output be in this case? Should we get True for both? Or is there a difference between the two? The following is the output we get on executing the above code snippet:

Identity:  True
Equality:  True

Interesting, it does seem that both the identity operator is and the equality operator == do the same thing since we’re getting the same results. But wait. Before you conclude that both of them are practically the same thing, try executing the following code snippet:

a = 5000
b = 5000

print("Identity: ", a is b)
print("Equality: ", a == b)

The above code gives the output:

Identity:  False
Equality:  True

Wait. What just happened?

Now would be a good time to define what these operators are and how they’re different. Remember, everything in python is an object and each object is assigned a memory location.

  • Identity Operators: Python identity operators (is, is not) are used to compare objects based on their identity. In the CPython interpreter, which you’re most likely to be using, the identity of an object refers to its location in memory. Other interpreters may have different ways of defining identity.
  • Equality Operators: Python equality operators (==, !=) are used to compare objects based on their values. It invokes the __eq__() class method of the left object which defines the rules for checking equality. But generally, these rules are defined such that if two objects have the same value irrespective of their memory locations, the equality operator == results in True.

For more on operators in python refer to this guide.

Okay, so why did the identity operator is result in True in the first example and False in the second? Surely, different variables should have different memory locations. Right? Let’s see for ourselves:

The python in-built function id() gives the memory location of an object. Let’s use it to see the locations referred to by the variables in the above two examples.

a = 50
b = 50

# location
print("Location of a:", id(a))
print("Location of b:", id(b))
# test
print("Identity: ", a is b)
print("Equality: ", a == b)

Output:

Location of a: 140733847780672
Location of b: 140733847780672
Identity:  True
Equality:  True

Since a and b had the same location the identity operator is resulted in True. Let’s see if that’s the case with the 2nd example:

a = 5000
b = 5000

# location
print("Location of a:", id(a))
print("Location of b:", id(b))
# test
print("Identity: ", a is b)
print("Equality: ", a == b)

Output:

Location of a: 1947716996112
Location of b: 1947716995856
Identity:  False
Equality:  True

Here, we find that a and b have been given different memory locations and thus the identity operator is resulted in False even though they had the same values.

Note that when variables a and b were assigned with value 50 they had the same memory location but when assigned with the value 5000, they had different memory locations. A good question to ask now would be –

This happens because the CPython interpreter interns smaller numbers at fixed memory locations. It means that the interpreter instantiates these values only once and it just have to look for its memory address whenever it is referenced. This is done because such values (like small numbers) are quite frequently used. Depending on your interpreter the range of such numbers might vary but it’s generally -5 to +256.

a = 256
b = 256
print(id(a))
print(id(b))

Output:

140733847787264
140733847787264

For 256, we get the same location due to interning.

a = 257
b = 257
print(id(a))
print(id(b))

Output:

1947707102640
1947707102672

But from 257 we see that we get different locations since they are not interned. There are other objects as well that are interned by the python interpreter.

The identity operators are actually quite useful when asserting whether an object is a specified singleton (objects with only one reference in memory) in python like None, True, or False because they check for identity and not run any other method based checks like ==

When you do –

a is None

The interpreter can only compare for identity and that cannot be overruled. Meaning, it’s a guaranteed check whether a is a reference to the None object and not something else.

With

a == None

The == operator invokes the a.__eq__() method which can give strange results depending on how it’s defined. See the example below –

class A:
    def __eq__(self, other):
        return True # I think I'm equal to everything

a = A()
print(a == 1)
print(a == None)
print(a is None)

Output:

True
True
False

You can see in the above example that the object a has been defined so as to all always return True whenever the class method __eq__() gets invoked, which is the case when you use == for comparison. And you should prefer is in such cases as it does not leave room for accidental results where the implementation could be different than expected.

Knowing when to use and not use the identity operator can save you a lot of time on future hair pulling. The following are the key pointers to remember –

  • Objects with the same value are often stored at different memory locations. Only a handful number of values are primed by the interpreter.
  • Always use the operators == or != when comparing values.
  • Use the identity operators to compare objects based on their identity. Example, when comparing with singleton objects like None, True, False, etc.

For more, refer to this detailed article by Real Python.


Subscribe to our newsletter for more informative guides and tutorials.
We do not spam and you can opt out any time.