Backend / Python core / 05_is_vs_equals.md

What is the difference between is and ==?

Updated 3 interview angles 4 min read source
On this page9
  1. == (Equality Operator)
  2. is (Identity Operator)
  3. Key differences
  4. Example with Lists
  5. Example with Small Integers
  6. Example with Small Integers within a Specific Range
  7. The one place is is required
  8. Summary
  9. Interview angle

What is the difference between is and ==?

In Python, both is and == are used for comparison, but they serve different purposes. Here’s a detailed explanation of each:

== (Equality Operator)

  • Purpose: Compares the values of two objects to check if they are equal.
  • Usage: Checks if the contents or data of two objects are the same.
  • Example:
    python
    a = [1, 2, 3]
    b = [1, 2, 3]
    
    # Output: True (since the lists have the same content)
    print(a == b)

is (Identity Operator)

  • Purpose: Compares the identity of two objects, checking if they refer to the same object in memory.
  • Usage: Checks if two objects are the exact same instance (i.e., have the same memory address).
  • Example:
    python
    a = [1, 2, 3]
    b = [1, 2, 3]
    
    print(a is b)  # Output: False (because a and b are two different objects in memory)
    
    # Comparing with the same object reference
    c = a
    print(a is c)  # Output: True (because a and c refer to the same object)

Key differences

  • == checks value equality, i.e., whether the objects have the same data or value.
  • is checks object identity, i.e., whether the objects refer to the same memory location.

Example with Lists

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

print(a == b)  # True: the values in the lists are the same
print(a is b)  # False: they are different objects in memory

Example with Small Integers

python
x = 1000
y = 1000
print(x == y)                         # True: same value
print(x is y)                         # True in one file: the compiler shares the constant
print(int("1000") is int("1000"))     # False: two objects built at runtime

Whether two equal large ints are the same object depends on how they were created, not on the value: constants in one code object are shared, so in a script x is y is True; values computed at runtime, or typed on separate REPL lines, are separate objects. Only -5 to 256 are cached for every source. That unpredictability is the point: never use is for value comparison.

Example with Small Integers within a Specific Range

python
x = 100
y = 100

print(x == y)  # True: the values are the same
# True: small integers (-5 to 256) are cached by Python, so they refer to the same object
print(x is y)

The one place is is required

Merged from the duplicate note that used to sit at 21_is_equal.md.

Comparing against None uses is, not ==, and this is the idiom rather than a style preference:

python
if value is None:        # correct
    ...

if value == None:        # works, and a class can lie about it
    ...

None is a singleton, so identity is the exact question being asked. And a class that defines __eq__ can make == None return True for something that is not None — is cannot be overridden, so it cannot be fooled. The same applies to True and False.

Summary

  • Use == when you want to check if two objects have the same value.
  • Use is when you want to check if two objects are the exact same instance (memory address), and always for None.

python
# Equality (==) vs Identity (is) Example

# Example 1: Using `==` with lists
a = [1, 2, 3]
b = [1, 2, 3]

print("Using == with lists:")
print(a == b)  # Output: True (the lists have the same content)
print(a is b)  # Output: False (different objects in memory)

# Example 2: Using `is` with the same object reference
c = a
print("\nUsing is with the same object reference:")
# Output: True (a and c refer to the same object)
print(a is c)

# Example 3: Using `==` and `is` with small integers
x = 1000
y = 1000

print("\nUsing == and is with large integers:")
print(x == y)  # Output: True (the values are the same)
print(x is y)  # Output: False (different objects in memory)

# Example 4: Using `==` and `is` with small integers within a specific range
x = 100
y = 100

print("\nUsing == and is with small integers (cached by Python):")
print(x == y)  # Output: True (the values are the same)
# Output: True (small integers are cached by Python, so they refer to the same object)
print(x is y)

# Example 5: Changing values in a list and comparing with `==` and `is`
a = [1, 2, 3]
b = [1, 2, 3]

print("\nUsing == and is after modifying lists:")
a[0] = 10  # Modifying list a
print(a == b)  # Output: False (values are different)
print(a is b)  # Output: False (they are still different objects in memory)

Interview angle 3

  • “is or ==?” - is compares identity, == compares value via __eq__. Use is only for None, True, False and sentinel objects.
  • “Why does a is b sometimes work for numbers and strings?” - interning. CPython caches small integers (-5 to 256) and some string literals, so identity accidentally matches value. It’s an implementation detail, and code relying on it breaks with different values or across versions.
  • “How do you compare floats?” - not with ==. Use math.isclose with an appropriate tolerance, because binary representation means 0.1 + 0.2 != 0.3.