is vs ==
Overview
The `==` operator compares the VALUES of two objects (equality), while the `is` operator compares the MEMORY ADDRESSES of two objects (identity). Two distinct objects can have the exact same value (`==` is True), but because they live in different places in memory, they are not the same object (`is` is False). Think of `==` as asking 'Do these two houses look identical?' and `is` as asking 'Are these two addresses pointing to the exact same house?'. In Python, `is` checks if `id(a) == id(b)`.
Mixing up `is` and `==` causes subtle bugs. Use `==` when you want to know if the data matches. Only use `is` when you need to know if two variables refer to the exact same object in memory (most commonly, checking `is None`).
Where used: FastAPI, Pydantic, Django
Why learn this
- Preventing subtle bugs when comparing collections
- Checking correctly for singletons like `None`
Code walkthrough
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
print(a is b)
Focus: print(a is b)
Aha moment
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
x = [1, 2, 3]
y = [1, 2, 3]
print(x is y)
Prediction: What will these two prints output?
Common guess: True, True
Even though `a` and `b` have identical contents (so `a == b` is True), lists are mutable objects. Python creates a brand new list in memory every time `[1, 2, 3]` is evaluated. Therefore `x` and `y` point to different memory addresses, and `x is y` is False.
Common mistakes
- Using `is` for value comparison: Using `is` instead of `==` for strings or numbers might sometimes work due to Python caching (interning) small integers and short strings, but it will randomly fail for larger values or dynamic inputs. Always use `==` for value comparison.
- Using `==` to check for None: While `x == None` works, the Pythonic and safer way is `x is None`. Some objects (like pandas DataFrames or SQLAlchemy models) override `==` to return an array of booleans or a query expression, which breaks the truth value testing. `is None` cannot be overridden.
Glossary
- identity
- The unique memory address or location of an object in a computer, confirming it is the exact same object. Example: `id(a) == id(b)` is the underlying check that `a is b` performs.
- singletons
- Objects or classes that are designed so that only one unique instance of them can ever exist in a program. Example: `None`, `True`, and `False` are singletons in Python — `x is None` is always the right check.
Recall questions
- What is the difference between `==` and `is`?
- When is it appropriate to use the `is` operator?
Understanding checks
What will the following code output?
`True` followed by `False`
`a` and `b` have the same values, so `a == b` is `True`. However, they are two distinct list objects in memory, so `a is b` evaluates to `False`.
Why is it recommended to use `x is None` instead of `x == None`?
Because `is` guarantees an identity check, preventing bugs if an object overrides `==` to behave unexpectedly.
Using `== None` triggers the `__eq__` method, which some libraries override to return custom objects instead of a simple boolean. `is None` directly compares memory addresses and cannot be overridden.
Practice tasks
Fix the singleton comparison
The `process_data` function currently uses `==` to check if the result is `None`. This works most of the time but can be unsafe. Modify the function to use the correct operator for checking identity against singletons like `None`.
Challenge
Safe None Checking
You are writing a database connector. Write a function `process_record(record)` that takes a record (which could be a dictionary or `None`). If `record` is exactly `None`, return the string 'No data'. Otherwise, return the string 'Processing'. You must use the safest comparison operator for `None`.
Continue learning
Previous: Variables as references
Next: Mutable vs immutable types
Next: Shallow vs deep copy