DEV Community

Cover image for Python's is vs ==: Stop Confusing Identity with Equality
Aaron Rose
Aaron Rose

Posted on

Python's is vs ==: Stop Confusing Identity with Equality

Have you ever introduced identical twins to your Python code, only to have it insist they're completely different people? Or worse, claimed two unrelated objects are the same just because they look alike? This common confusion stems from mixing up Python's is and == operators. Understanding the difference is a fundamental step toward writing correct and Pythonic code.

The Fundamental Difference: Identity vs. Equality

At its core, the distinction is simple yet crucial:

  • == (Equality): Checks if two objects have the same value.
  • is (Identity): Checks if two variables point to the exact same object in memory.

Think of it like this: == asks "Do you two look the same?" while is asks "Are you literally the same person?"

Let's make this concrete with a custom class:

class Car:
    def __init__(self, model, color):
        self.model = model
        self.color = color

    # This method defines what happens when we use ==
    def __eq__(self, other):
        if not isinstance(other, Car):
            return False
        return self.model == other.model and self.color == other.color

# Create two different cars that look identical
my_car = Car("Tesla Model 3", "Red")
your_car = Car("Tesla Model 3", "Red")
same_car = my_car  # This is just another name for the same object

print(my_car == your_car)   # True - Same make and color (value)
print(my_car is your_car)   # False - They are different vehicles (identity)
print(my_car is same_car)   # True - Same exact object (identity)
Enter fullscreen mode Exit fullscreen mode

When Python Tricks You: The Interning Phenomenon

Python sometimes optimizes memory by reusing immutable objects, a process called interning. This can lead to surprising results if you mistake it for standard behavior.

# Small integers and short strings are often interned
a = "hello"
b = "hello"
print(a is b)  # True - Python reused the same string object

# But this isn't guaranteed behavior!
x = 1000
y = 1000
print(x is y)  # False - Different objects (in most implementations)
Enter fullscreen mode Exit fullscreen mode

This behavior explains why 1000 is 1000 might be False while 5 is 5 is often True—Python caches small integers (-5 to 256) and short strings for performance. Never rely on interning for your program's logic; always use == for value comparison.

The One Place is Reigns Supreme: None Checking

There's one universal case where you should always use is: checking for None.

# ✅ The Pythonic way
if value is None:
    print("Got nothing!")

# ❌ Avoid this
if value == None:
    print("Works but isn't ideal")
Enter fullscreen mode Exit fullscreen mode

Why is is the better choice? Because None is a singleton in Python—there is only one instance of it in existence. Using is is both faster (a simple pointer comparison) and more readable. It's a established convention that every experienced Python developer expects.

Common Pitfalls That Trip Developers Up

This distinction becomes critical when working with mutable collections like lists, which always create new objects.

# Lists always create new objects, even with the same content
list_a = [1, 2, 3]
list_b = [1, 2, 3]
print(list_a == list_b)  # True - Same values
print(list_a is list_b)  # False - Always different objects

# This is a very common beginner mistake
def add_to_list(item, target=[]):
    # 🚨 Warning: using a mutable default argument!
    target.append(item)
    return target

list_1 = add_to_list('a') # Returns ['a']
list_2 = add_to_list('b') # Returns ['a', 'b'] (!)
print(list_1 is list_2)   # True - They're the same object!
Enter fullscreen mode Exit fullscreen mode

The above example shows why using is can help you debug unexpected behavior related to mutable objects and identity.

Performance and the Golden Rule

There's a minor performance benefit to using is when appropriate. The is operator only compares memory addresses (a single, fast operation), while == might need to check multiple values or call a custom __eq__ method.

The Golden Rule: Let your intent guide your choice.

  • Use is when you care about object identity (None, singletons, checking if it's the exact same object).
  • Use == when you care about value equality (numbers, strings, custom data).

By understanding and applying this simple distinction, you'll avoid subtle bugs and write clearer, more intentional code. Remember: twins may look identical, but they're still different people. Your Python code should know the difference.


Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.

Top comments (0)