This is one of the most commonly misused Python features and it fails silently, which makes it especially dangerous in production code.
a = "hello"
b = "hello"
print(a == b)
print(a is b)
Both print True. Safe, right?
Now try this:
a = "hello world"
b = "hello world"
print(a == b)
print(a is b)
a == b prints True. a is b might print False.
Same code structure. Different result. Here is exactly why.
What is and == Actually Check
== checks value equality. Do these two objects represent the same value?
is checks identity equality. Are these two names pointing to the exact same object in memory?
Two objects can be equal in value while being completely different objects in memory.
String Interning
Python automatically interns some strings. Interning means Python reuses a single object for multiple names with the same value, rather than creating separate objects.
Short strings that look like valid Python identifiers are automatically interned. Longer strings or strings with spaces are not always interned.
a = "hello"
b = "hello"
print(a is b) # True -- both point to the same interned object
a = "hello world"
b = "hello world"
print(a is b) # False -- two separate objects (implementation dependent)
The behavior for longer strings is implementation dependent and version dependent. You cannot rely on it.
Integer Caching
Python caches integers from -5 to 256. Integers in this range are always the same object regardless of how many names point to them.
a = 100
b = 100
print(a is b) # True -- cached integer, same object
a = 1000
b = 1000
print(a is b) # False -- outside cache range, separate objects
a = 256
b = 256
print(a is b) # True -- last cached integer
a = 257
b = 257
print(a is b) # False -- first uncached integer
The Interview Trap
x = None
y = None
print(x is y) # True -- None is a singleton
print(x == y) # True
x = []
y = []
print(x is y) # False -- two separate empty list objects
print(x == y) # True -- both represent empty lists
The canonical use case for is is checking against None, True, and False. These are singletons in Python. Every None in your program is the same object.
# Correct pattern
if value is None:
handle_missing()
# Incorrect pattern (works by accident, not by design)
if value == None:
handle_missing()
The == version works because NoneType.__eq__ is implemented but using is is the semantically correct choice and is what PEP 8 requires.
The Practical Rule
Use == for value comparison in all application code.
Use is only for checking against None, True, and False.
Never use is to compare strings or integers in application code, even if it works in testing.
Practice identity vs equality problems at PyCodeIt.
Top comments (0)