Difference Between the == and is Operators in Python

Posted: | Tags: Python

In Python, the == operator checks if the values of two objects are equal, while the is operator checks if two objects are identical.

Value comparison using the == operator

The == operator returns True if the values of the two objects are equal and False if they are not.

a = 100
b = 100
c = 200
print(a == b)
# True

print(a == c)
# False
source: eq_is.py

On the other hand, the != operator returns True if the values of the two objects are not equal and False if they are equal.

print(a != b)
# False

print(a != c)
# True
source: eq_is.py

Value comparison for numbers

For numeric types such as integers (int), floating point numbers (float), and complex numbers (complex), values are compared even if the types are different.

print(100 == 100.0)
# True

print(100 == 100 + 0j)
# True
source: eq_is.py

Additionally, the booleans (bool) are a subclass of the integers (int). True is treated as 1, and False is treated as 0.

print(1 == True)
# True

print(0.0 == False)
# True
source: eq_is.py

To check if both the value and type are equal, use type() and and.

a = 100
b = 100.0
print(a == b)
# True

print(a == b and type(a) == type(b))
# False
source: eq_is.py

Note that strings (str) are not considered equal to numbers despite their content. To compare a string's value with a number, convert the string to a number using int() or float().

print(100 == '100')
# False

print(100 == int('100'))
# True
source: eq_is.py

Identity comparison using the is operator

The is operator returns True if the two objects are identical and False if they are not.

Even if the values are the same (the result of == is True), is returns False if the objects are different.

l1 = [1, 2, 3]
l2 = [1, 2, 3]
print(l1 == l2)
# True

print(l1 is l2)
# False
source: eq_is.py

When one variable is assigned to another, both point to the same object, and is returns True.

l3 = l1
print(l1 is l3)
# True
source: eq_is.py

For mutable objects like lists and dictionaries, if two variables point to the same object and one is changed, the other also changes.

l1[0] = 100
print(l1)
# [100, 2, 3]

print(l2)
# [1, 2, 3]

print(l3)
# [100, 2, 3]
source: eq_is.py

In contrast to the is operator, the is not operator returns True if the two objects are not identical and False if they are identical.

print(l1 is not l2)
# True

print(l1 is not l3)
# False
source: eq_is.py

Identity is determined by the id() function

The built-in function id() is used to determine the object's identity.

print(id(l1))
# 4388188480

print(id(l2))
# 4388187456

print(id(l3))
# 4388188480
source: eq_is.py

You can verify that the same objects (in the example, l1 and l3) have the same identification value.

Identity comparison for immutable types

Be cautious when using is and is not comparisons for immutable objects like integers (int) and strings (str).

When creating a new object, a reference to an existing object may or may not be returned.

For example, when creating an int value in the range of -5 to 256, a reference to an existing object is returned. However, values outside this range are created as separate objects.

The current implementation keeps an array of integer objects for all integers between -5 and 256. When you create an int in that range you actually just get back a reference to the existing object. Integer Objects — Python 3.11.3 documentation

a = 256
b = 256
print(a is b)
# True

a = 257
b = 257
print(a is b)
# False
source: eq_is.py

For strings (str), those containing only alphanumeric characters and underscores (_) are cached, and a reference to the cached object is returned. However, strings with other characters are created as separate objects.

a = 'abc_123'
b = 'abc_123'
print(a is b)
# True

a = 'abc_123?'
b = 'abc_123?'
print(a is b)
# False
source: eq_is.py

Results may vary depending on the code structure, such as creating identical objects when assigning values to two variables in the same line.

a, b = 257, 257
print(a is b)
# True

a, b = 'abc_123?', 'abc_123?'
print(a is b)
# True
source: eq_is.py

Also, these are the results when executed in CPython 3.11, and may vary depending on the implementation or version.

Although is is faster than ==, and you may use it if you understand the specifications, it is generally recommended to use == instead of is when comparing immutable objects.

== operator can be overloaded, is operator cannot

The == and != operators have corresponding special methods __eq__ and __ne__, which can be overloaded.

class MyClass:
    def __eq__(self, other):
        return '__eq__'

    def __ne__(self, other):
        return '__ne__'

my_obj = MyClass()
print(my_obj == 100)
# __eq__

print(my_obj != 100)
# __ne__
source: eq_is.py

The above example is an extreme case where == and != operations always return '__eq__' and '__ne__', but user-defined class == and != operations may be customized.

On the other hand, there are no corresponding special methods for the is and is not operators, and they cannot be overloaded. They always compare and determine the identity of objects.

Check for None with is None or is not None

None is a built-in constant that represents the absence of a value.

In Python's coding convention PEP8, comparisons with None should use is and is not instead of == and !=.

Comparisons to singletons like None should always be done with is or is not, never the equality operators. PEP 8 – Style Guide for Python Code | peps.python.org

a = None
print(a is None)
# True

print(a is not None)
# False
source: eq_is.py

Although not explicitly stated in PEP8, the following reasons can be considered:

  1. None is a singleton (the only instance of NoneType), so there is no concern that the result of is will change depending on the value, as in the examples of integers and strings mentioned above.
  2. is and is not are not overloadable and are safe, while == and != may be customized by operator overloading.
  3. is and is not are faster than == and !=.

For example, depending on the __eq__ implementation, == None might return True for non-None values. However, is None always correctly determines the value.

class MyClass:
    def __eq__(self, other):
        return True

my_obj = MyClass()
print(my_obj == None)
# True

print(my_obj is None)
# False
source: eq_is.py

Note that nan, which represents a "not a number", is a float value and is different from None. To check for nan, use math.isnan() or numpy.isnan().

Related Categories

Related Articles