1. What Are Identity Operators?
Identity operators in Python allow you to check whether two variables point to the same object in memory, not just whether their values are equal.
Python provides two identity operators:
| Operator | Description |
|---|---|
is |
Returns True if both variables refer to the same object in memory. |
is not |
Returns True if both variables refer to different objects in memory. |
Why Are Identity Operators Important?
- They are useful for checking memory references, not just equality.
- Commonly used when comparing with
None.
if variable is None:
print("No value assigned")
FYI: Don’t miss out on mastering Python operators. Check out our complete Python Operators guide for arithmetic, logical, assignment, membership, and more.
2. Identity Operators vs Equality Operators
While equality operators compare the values of two variables, identity operators check whether both variables refer to the same object in memory.
The table below highlights the key differences.
| Type | Operator | Compares | Example |
|---|---|---|---|
| Equality | == | Values | a == b → True if values match |
| Identity | is | Memory Address | a is b → True if both refer to the same object |
Explanation:
Equality (==) checks content, while identity (is) checks memory location.
3. Examples: Identity Operators in Action
To better understand how identity operators behave in real programs, let’s explore practical examples using different data types and scenarios.
3.1. Identity with Simple Integers (Immutable Types)
Description:
When working with integers in Python, it’s important to remember that small integer objects (usually between -5 and 256) are internally cached by Python for performance optimization. This means that if two variables hold the same small integer value, they actually point to the same memory location — making the is operator return True.Example:
x = 100
y = 100
print(x is y) # True (small integers are cached)
print(x == y) # True (values are equal)
Explanation:
Here, both x and y contain the integer 100, which lies within Python’s small integer cache range. Therefore, they refer to the same object in memory. x is y → returns True, because both variables point to the same memory location. x == y → returns True, because their values are equal.Insight:
This behavior helps Python optimize memory and execution speed, especially when frequently using small integer values in loops or arithmetic operations.
3.2. Identity with Large Integers
Description:
When dealing with larger integers in Python, the behavior of the is operator changes compared to small integers. Python does not cache large integers (beyond the range of -5 to 256).
This means that even if two variables hold the same large integer value, they are stored in different memory locations, resulting in is returning False, even though their values are equal.
Example:
a = 1000
b = 1000
print(a is b) # False (different memory objects)
print(a == b) # True (values still equal)
Explanation:
In this example, both a and b have the value 1000, but Python creates separate objects in memory for each because the number lies outside the small integer caching range.
a is b → returns False, since they occupy different memory locations.
a == b → returns True, because their values are the same.
Insight:
This behavior highlights the distinction between object identity and value equality in Python. When working with large integers, it’s essential to remember that identical-looking values might not share the same memory address — an important concept when optimizing performance or debugging complex code.
3.3. Identity with Lists (Mutable Types)
Description:
When working with mutable objects such as lists, Python handles memory allocation differently compared to immutable types like integers or strings. Even if two lists contain the same elements in the same order, Python treats them as two separate objects in memory — meaning the is operator will return False, while == will return True.
Example:
list1 = [1, 2, 3]
list2 = [1, 2, 3]
print(list1 == list2) # True (same values)
print(list1 is list2) # False (different memory addresses)
Explanation:
In this case, both list1 and list2 look identical because they contain the same elements: [1, 2, 3]. However, since lists are mutable, Python creates distinct memory objects for each one. list1 == list2 → returns True, because their values match.
list1 is list2 → returns False, because they occupy different memory locations.
Insight:
This distinction is crucial when dealing with mutable objects in Python. Even if two lists appear identical, modifying one will not affect the other. The is operator checks if two variables reference the exact same object, not just if they contain identical data.
3.4. Assigning the Same Reference
Description:
When a variable is directly assigned to another, both variables point to the same object in memory. This means that any change made through one variable automatically reflects in the other — because both refer to the same underlying data.
Example:
list3 = [10, 20]
list4 = list3
print(list3 is list4) # True
Explanation:
In this example, list4 is not a copy of list3; rather, it’s just another reference to the same list object.
- list3 is list4 → returns True, because both variables share the same memory address.
If one list is modified, the changes will appear in both, since they are essentially two names for the same object.
Insight:
This behavior is especially important when working with mutable data types like lists, sets, and dictionaries.
If you need an actual copy (not just another reference), use copy() or the copy module.
Example (Creating a Copy):
import copy
list5 = copy.copy(list3) # Creates a shallow copy
print(list5 is list3) # False (different objects)
3.5. Using is not – Checking for Different Objects
Description:
The is not operator in Python is used to verify whether two variables do not point to the same memory location. Even if their values appear identical, they can still be stored as separate objects in memory — especially when dealing with mutable types like lists or dictionaries.
Example:
x = [1, 2]
y = [1, 2]
print(x is not y) # True (different objects)
Explanation:
In this example, x and y both hold lists with the same elements [1, 2]. However, Python treats them as two distinct list objects in memory.
x is not y → returns True, because each variable refers to a different object, even though the contents are equal.
x == y would return True, since their values match.
Insight:
The is not operator is often used for identity comparison — to ensure that two references are not pointing to the same memory object.
It’s also frequently used in conditions such as:
if variable is not None:
print("Variable has a value assigned.")
3.6. Identity Comparison with None in Python
Description:
In Python, None represents the absence of a value or a null object. Using identity operators (is and is not) is the recommended way to check for None, rather than using equality operators (== or !=).
Example:
value = None
if value is None:
print("No value assigned yet")
if value is not None:
print("Value exists")
Explanation:
value is None → returns True if the variable does not reference any object (i.e., it’s uninitialized or explicitly set to None).
value is not None → returns True if the variable references an object (has a value assigned).
Insight:
Using is and is not for None checks ensures reliable and readable code, as it explicitly tests object identity rather than value equality. This approach is widely considered a Python best practice.
Real-World Use Case:
def fetch_user(user_id):
user = database.get(user_id)
if user is None:
return "User not found"
return user
Here, checking user is None avoids potential pitfalls when comparing objects that might evaluate as false in a Boolean context (like empty lists or strings).
4. Behind the Scenes: Understanding Object IDs in Python
In Python, every object has a unique identity represented by its memory address. The id() function allows you to inspect this memory address, which helps explain how the is operator works under the hood.
Example:
a = [1, 2]
b = [1, 2]
# Different objects, different memory addresses
print(id(a), id(b)) # e.g., 140590123456000 140590123456128
print(a is b) # False
# Assigning the same reference
c = a
print(id(a), id(c)) # Same memory address
print(a is c) # True
Explanation:
id(a) → returns a unique identifier (memory address) of object a.
a is b → compares memory addresses; returns False because a and b are two distinct objects.
c = a → now c points to the same object as a; hence a is c returns True.
Insight:
The is operator doesn’t compare values — it compares object identities. Understanding this is crucial when working with mutable types like lists, dictionaries, and sets, where two objects can have the same content but reside in different memory locations.
5. Python Identity Operators – Quick Reference Table
| Expression | Description | Result |
|---|---|---|
| a is b | Returns True if a and b refer to the same object in memory | True / False |
| a is not b | Returns True if a and b refer to different objects | True / False |
| a == b | Returns True if the values of a and b are equal (ignores memory location) | True / False |
| a is None | Recommended way to check if a variable is None (preferred over == None) | True / False |
Insight:
Use is and is not when you need to check object identity, not just equality.
== compares values, which is sufficient for immutable types like integers, strings, or tuples.
Checking a is None is the Pythonic way to verify if a variable is uninitialized or explicitly set to None.