Equality (==) Operator vs is Keyword in Python: What is the Difference

Learn about the equality operator == and the is keyword, the difference between both, and when to use them.

Picture of Nsikak Imoh, author of Macsika Blog
null
null

Table of Content

The equality operator == and is keyword are two features in Python that are used to compare values.

The equality operator == compares the values and is operator compares the references.

In this post, you will learn about the equality operator == and the is keyword, the difference between both, and when to use them.

What is the Equality (==) Operator?

The equality operator is used to compare two values of the objects/variables.

It returns True if both the values are equal and False if they are not equal.

This is useful when you want to check if two objects contain the same content or not.

Example of how to use the Equality (==) Operator

a = 1000  
b = 1000  
print(a == b)
Highlighted code sample.

Output

True
Highlighted code sample.

The equality check returns True as both the values are equal.

What is the “is” Keyword Operator?

The “is” keyword operator is used to check if two variables are pointing to the same object in memory.

This is useful when you want to check if the object is a singleton (objects with one reference in memory) like None, True, False, etc. as they check for identity.

It also checks if the object is of a particular type or not.

Example of how to use the “is” Keyword Operator

a = [1, 2, 3]  
b = a
print(id(a))
print(id(b)) 
print(a is b) 
Highlighted code sample.

Output

# 140545544215872
# 140545544215872
# True
Highlighted code sample.

In the above example, the result of the identity operator is True as both the values have the same location in the memory.

id() is the Python built-in function that returns the memory location of an object.

Let's see another example:

a = [1, 2, 3]  
b = [1, 2, 3]
print(id(a))
print(id(b)) 
print(a is b) 
Highlighted code sample.

Output

4339901952
4340797632
False
Highlighted code sample.

In the above example, the result of the identity operator is False, as both the values have different locations in the memory.

What's the difference between the equality (==) operator and “is” in Python?

The equality operator == is used for value equality to know if two objects have the same value while the is keyword is for reference equality to know if two variables point to the same object in memory.

==: check for equality - the semantics are that equivalent objects (that aren't necessarily the same object) will test as equal.

According to the documentation:

The operators <, >, ==, >=, <=, and != compare the values of two objects.

is: check for identity - the semantics are that the object (as held in memory) is the object.

According to the documentation:

*The operators is and is not test for object identity: x is y is true if and only if x and y are the same objects.

Object identity is determined using the id() function. x is not y yields the inverse truth value.*

Thus, the check for identity is the same as checking for the equality of the IDs of the objects. That is,

a is b
Highlighted code sample.

is the same as:

id(a) == id(b)
Highlighted code sample.

Where id is the built-in function that returns an integer that “is guaranteed to be unique among simultaneously existing objects” (see help(id)) and where a and b are any arbitrary objects.

When Should is Keyword Operator be used?

The is Keyword Operator should be used when:

  • you want to compare a value to a Python constant. The constants in Python are:

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • classes (for example int is int or int is float)
    • there could be additional constants in built-in modules or 3rd party modules. For example np.ma.masked from the NumPy module.

Other situations where is keyword operator can be used include:

  • None
  • enum values (when using Enums from the enum module)
  • modules
  • class objects resulting from class definitions
  • function objects resulting from function definitions
  • Anything else that should only exist once in memory (all singletons, generally)
  • A specific object that you want by identity

When Should == Operator be Used?

Here are situations where == operator can be used:

  • numbers, including integers
  • strings
  • lists
  • sets
  • dictionaries
  • custom mutable objects
  • other built-in immutable objects, in most cases

The PEP 8, the official Python style guide for the standard library also mentions two use-cases for is:

  1. Comparisons to singletons like None should always be done with is or is not, never the equality operators.

  2. Also, beware of writing if x when you really mean if x is not None – e.g. when testing whether a variable or argument that defaults to None was set to some other value.

The other value might have a type (such as a container) that could be false in a boolean context!

Issues with using 'is' to check for Equality

There are some inconsistent behaviors in Python when you use 'is' to check for Equality.

Let's run this small example.

a = 1000  
b = 1000  
print(a == b)
Highlighted code sample.

Output

 True  
 a is b  
 False
Highlighted code sample.

The behavior is expected, just like what we saw in the previous example.

Let's now replace 1000 with 100.

c = 100  
d = 100  
print(c == d)
Highlighted code sample.

Output

True  
c is d  
True
Highlighted code sample.

What happened here? This is inconsistent with the previous result.

It turns out, the reference implementation of Python caches integer objects in the range -5…256 as singleton instances for performance reasons.

You can see that when we have small numbers like 50 in the first example, they have same the memory locations. But when we have large numbers like 500 in the second example, they have different memory locations. Why?

This is because interpreters in CPython interns smaller numbers to a fixed memory location to save memory as they are frequently used.

Generally, the range of numbers is -5 to +256, but it can vary according to your interpreter.

Any number outside this range is interned to a different memory location. That's why a large number like 500 returns False.

The same thing happens for strings as well.

Let's see the example below:

>>> s = b = 'somestr'
>>> s == b, s is b, id(s), id(b)
(True, True, 4555519392, 4555519392)

Highlighted code sample.

Now everything seems fine.

>>> s = 'somestr'
>>> b = 'somestr'
>>> s == b, s is b, id(s), id(b)
(True, True, 4555519392, 4555519392)

Highlighted code sample.

That's expected too.

>>> s1 = b1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a'
>>> s1 == b1, s1 is b1, id(s1), id(b1)
(True, True, 4555308080, 4555308080)

>>> s1 = 'A quick brown fox jumps over the lazy dog'
>>> b1 = 'A quick brown fox jumps over the lazy dog'
>>> s1 == b1, s1 is b1, id(s1), id(b1)
(True, False, 4555308176, 4555308272)

Highlighted code sample.

Now that's unexpected.

Inferring equality from identity

If is is true, equality can usually be inferred - logically, if an object is itself, then it should test as equivalent to itself.

In most cases, this logic is true, but it relies on the implementation of the __eq__ special method. As the docs say,

The default behavior for equality comparison (== and !=) is based on the identity of the objects. Hence, equality comparison of instances with the same identity results in equality, and equality comparison of instances with different identities results in inequality. A motivation for this default behavior is the desire that all objects should be reflexive (i.e. x is y implies x == y).

and in the interests of consistency, recommends:

Equality comparison should be reflexive. In other words, identical objects should compare equal:

x is y implies x == y

We can see that this is the default behavior for custom objects:

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

Highlighted code sample.

The contrapositive is also usually true - if something tests as not equal, you can usually infer that they are not the same object.

Since tests for equality can be customized, this inference does not always hold true for all types.

Extra point to keep in mind

A notable exception is nan - it always tests as not equal to itself:

>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan           # !!!!!
False
Highlighted code sample.

Checking for identity can be a much quicker check than checking for equality (which might require recursively checking members).

But it cannot be substituted for equality where you may find more than one object as equivalent.

Note that comparing the equality of lists and tuples will assume that identity of objects are equal (because this is a fast check).

This can create contradictions if the logic is inconsistent - as it is for nan:

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Highlighted code sample.

Conclusion

In this tutorial, you have learned the difference between the equality operator and the is keyword and how to use them.

The difference between the equality operator and is operator is that is operator checks the identity of the objects and the equality operator checks the equality of the objects.

Do not use is to compare integers and strings.

If you learned from this tutorial, or it helped you in any way, please consider sharing and subscribing to our newsletter.

Please share this post and for more insightful posts on business, technology, engineering, history, and marketing, subscribe to our newsletter.

Get the Complete Code of Python Code Snippets on Github.

Connect with me.

Need an engineer on your team to grease an idea, build a great product, grow a business or just sip tea and share a laugh?