0
0
PyTesttesting~15 mins

Checking identity (is, is not) in PyTest - Deep Dive

Choose your learning style9 modes available
Overview - Checking identity (is, is not)
What is it?
Checking identity means verifying if two variables point to the exact same object in memory. In Python, the operators 'is' and 'is not' are used for this purpose. Unlike equality (==), which checks if values are the same, identity checks if the objects themselves are the same. This is important in testing to ensure objects are not just equal but actually the same instance.
Why it matters
Without identity checks, tests might pass even if two variables are different objects with the same value. This can hide bugs where object uniqueness matters, such as caching, singleton patterns, or mutable objects. Identity checks help catch subtle errors that equality checks miss, ensuring more reliable and accurate tests.
Where it fits
Before learning identity checks, you should understand basic Python variables, objects, and equality (==) comparisons. After mastering identity checks, you can explore advanced testing concepts like mocking, fixtures, and test isolation in pytest.
Mental Model
Core Idea
Identity checks verify if two variables point to the exact same object in memory, not just equal values.
Think of it like...
It's like checking if two keys are the same physical key, not just keys that open the same door.
Variable A ──┐
             │
             ├─> [Object 1 in memory]
             │
Variable B ──┘

'is' checks if both arrows point to the same box (Object 1).
Build-Up - 6 Steps
1
FoundationUnderstanding Python objects and variables
🤔
Concept: Variables in Python are labels pointing to objects stored in memory.
In Python, when you write x = [1, 2, 3], x points to a list object in memory. Another variable y = x points to the same list object, not a copy. This means x and y share the same object.
Result
Both x and y refer to the same list object in memory.
Understanding that variables are references to objects is key to grasping identity checks.
2
FoundationDifference between equality and identity
🤔
Concept: Equality (==) checks if values are the same; identity (is) checks if objects are the same.
For example, two lists with the same content are equal (==) but may not be identical (is). x = [1, 2] y = [1, 2] x == y # True x is y # False
Result
Equality is True because values match; identity is False because they are different objects.
Knowing this difference prevents confusion when tests fail unexpectedly.
3
IntermediateUsing 'is' and 'is not' in pytest assertions
🤔Before reading on: do you think 'assert a is b' and 'assert a == b' always behave the same? Commit to your answer.
Concept: Pytest supports identity checks using 'assert a is b' and 'assert a is not b' to verify object sameness or difference.
Example: def test_identity(): a = [1, 2] b = a c = [1, 2] assert a is b # passes, same object assert a is not c # passes, different objects assert a == c # passes, equal values
Result
Tests pass when identity matches expectations, fail otherwise.
Using identity assertions helps catch bugs where object uniqueness matters, beyond value equality.
4
IntermediateCommon pitfalls with immutable objects and identity
🤔Before reading on: do you think small integers always have the same identity in Python? Commit to yes or no.
Concept: Python caches some immutable objects like small integers and strings, so identity may be True unexpectedly.
Example: a = 100 b = 100 assert a is b # Usually True due to caching x = 1000 y = 1000 assert x is not y # Usually True, different objects This caching can confuse identity checks.
Result
Identity checks on small immutable objects may pass due to caching, but not always for larger values.
Knowing caching behavior prevents false assumptions about identity with immutable types.
5
AdvancedIdentity checks in mutable vs immutable contexts
🤔Before reading on: do you think identity checks are more important for mutable or immutable objects? Commit to your answer.
Concept: Identity matters more for mutable objects because changes affect the object itself; immutable objects cannot change, so identity is less critical.
Mutable objects like lists or dicts can be changed in place. If two variables share the same mutable object (identity), changes via one affect the other. Immutable objects like strings or tuples cannot be changed after creation, so identity is less often critical. Example: lst1 = [1] lst2 = lst1 lst2.append(2) assert lst1 == [1, 2] # True If identity was not checked, tests might miss shared mutations.
Result
Identity checks help detect shared mutable objects that can cause side effects.
Understanding when identity matters helps write more precise and reliable tests.
6
ExpertSubtle bugs from mistaken identity assumptions
🤔Before reading on: can two objects be equal but cause bugs if mistaken as identical? Commit yes or no.
Concept: Mistaking equal but distinct objects as identical can cause bugs, especially with mutable objects or caching mechanisms.
Example bug: cache = {} key1 = (1, 2) key2 = (1, 2) cache[key1] = 'value' # If code assumes key1 is key2 by identity, it may fail to retrieve 'value' because keys are equal but not identical. In tests, asserting identity instead of equality or vice versa can mask such bugs. Pytest identity checks help catch these subtle issues.
Result
Tests that misuse identity checks may pass or fail incorrectly, hiding real bugs.
Recognizing the difference between identity and equality is crucial to avoid subtle, hard-to-find bugs in production.
Under the Hood
Python stores objects in memory and variables hold references (pointers) to these objects. The 'is' operator compares these references directly, checking if two variables point to the same memory address. The '==' operator calls the __eq__ method of objects to compare their values, which can be overridden. Identity checks are thus a direct pointer comparison, very fast and unambiguous.
Why designed this way?
Python separates identity and equality to allow flexible value comparisons while preserving the ability to detect object uniqueness. This design supports mutable objects, caching, and optimization techniques. Alternatives like conflating identity and equality would limit expressiveness and cause bugs in mutable object handling.
Variables and Objects:

┌─────────┐     ┌───────────────┐
│  var A  │────▶│ Object at 0x1 │
└─────────┘     └───────────────┘

┌─────────┐     ┌───────────────┐
│  var B  │────▶│ Object at 0x1 │
└─────────┘     └───────────────┘

'is' compares if var A and var B point to the same box (0x1).

For equality:

┌─────────┐     ┌───────────────┐
│  var C  │────▶│ Object at 0x2 │
└─────────┘     └───────────────┘

Even if Object at 0x2 has same value as Object at 0x1, 'is' is False but '==' can be True.
Myth Busters - 3 Common Misconceptions
Quick: Does 'a is b' mean 'a == b' is always True? Commit yes or no.
Common Belief:Many believe that if two variables are identical, they must also be equal.
Tap to reveal reality
Reality:Identity means same object, but equality depends on value comparison. Two identical objects are always equal, but two equal objects are not necessarily identical.
Why it matters:Confusing identity with equality can cause tests to miss bugs where objects have same values but different identities, leading to unexpected side effects.
Quick: Do you think 'is' works the same for all data types? Commit yes or no.
Common Belief:Some think 'is' behaves consistently across all Python types.
Tap to reveal reality
Reality:'is' checks identity for all types, but caching of small immutable objects (like small ints and strings) can make 'is' True unexpectedly for some values.
Why it matters:Assuming 'is' always means different objects can cause false positives or negatives in tests, especially with immutable types.
Quick: Can two variables be equal but cause bugs if mistaken as identical? Commit yes or no.
Common Belief:People often assume equal objects can be treated as identical safely.
Tap to reveal reality
Reality:Equal but distinct objects can behave differently if mutated or used as keys, causing bugs if identity is assumed incorrectly.
Why it matters:Mistaking equality for identity can hide bugs in caching, state management, or data structures.
Expert Zone
1
Identity checks are critical in testing singleton patterns where only one instance should exist.
2
Python's interning of small integers and strings can cause identity checks to pass unexpectedly, requiring careful test design.
3
Mutable default arguments in functions can cause identity-related bugs that are hard to detect without explicit identity assertions.
When NOT to use
Avoid using identity checks for comparing values of immutable objects where equality suffices. Instead, use '==' for value comparison. Use identity checks primarily when object uniqueness or shared state matters, such as with mutable objects or caching.
Production Patterns
In production tests, identity checks verify that mocks or fixtures return the same object instance. They also ensure that caching mechanisms reuse objects correctly. Identity assertions help detect unintended object duplication or mutation side effects.
Connections
Memory management
Identity checks rely on understanding how variables reference memory locations.
Knowing memory management helps understand why 'is' compares object addresses, clarifying identity behavior.
Singleton design pattern
Identity checks verify that only one instance of a class exists.
Understanding identity is essential to test and implement singletons correctly.
Philosophy of identity
Both deal with what it means for two things to be the same entity versus just similar.
Exploring philosophical identity sharpens thinking about object sameness versus equality in programming.
Common Pitfalls
#1Using '==' when identity check is needed
Wrong approach:assert a == b # passes if values equal, but objects may differ
Correct approach:assert a is b # passes only if same object
Root cause:Confusing equality with identity leads to tests that miss shared object bugs.
#2Assuming 'is' works reliably for all integers and strings
Wrong approach:assert 1000 is 1000 # may fail due to no interning
Correct approach:assert 1000 == 1000 # reliable value equality
Root cause:Not knowing Python's caching behavior causes flaky identity tests.
#3Using 'is not' incorrectly with mutable objects
Wrong approach:assert a is not b # expecting different objects but both point to same mutable object
Correct approach:assert a is b # correctly asserts same mutable object
Root cause:Misunderstanding variable references causes wrong assumptions about object uniqueness.
Key Takeaways
Identity checks verify if two variables point to the exact same object in memory, unlike equality which compares values.
Using 'is' and 'is not' in pytest assertions helps catch bugs related to object uniqueness and shared mutable state.
Python caches some immutable objects, so identity checks on small integers or strings may behave unexpectedly.
Identity matters most for mutable objects where changes affect the object itself and all references to it.
Confusing identity with equality can cause subtle bugs and unreliable tests; understanding their difference is essential.