1. Identity (`is`) vs. Equality (`==`)
Memory Pointer vs. Value Equivalence
- Equality operator (==) checks whether two objects have equivalent contents by delegating to `__eq__()`.
- Identity operator (`is`) checks whether two references point to the exact same memory address: `id(a) == id(b)`.
- CPython pre-allocates and caches small integers (-5 to 256) and interned string literals for memory efficiency.
list1 = [1, 2, 3]
list2 = [1, 2, 3]
print("list1 == list2:", list1 == list2) # True (equal contents)
print("list1 is list2:", list1 is list2) # False (distinct heap objects!)
# Comparing to None must always use 'is'
x = None
print("x is None:", x is None)
💡 Key Takeaway: Always use `==` for comparing values, and reserved `is` strictly for singleton checks like `x is None`.