How to compare two dictionaries in Python
Learn how to compare two dictionaries in Python. Discover different methods, tips, real-world applications, and how to debug common errors.

You often need to compare dictionaries in Python to check for equality, find differences, or merge data. Python provides several direct methods to handle these comparisons with efficiency.
Here, you'll explore techniques from simple equality checks with == to complex diffs. You'll also find real-world applications, practical tips, and advice to debug common comparison issues, so you can choose the best method for your needs.
Using the equality operator (==)
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 2, 'a': 1}
dict3 = {'a': 1, 'b': 3}
print(dict1 == dict2) # Order doesn't matter
print(dict1 == dict3) # Values matter--OUTPUT--True
False
The equality operator (==) offers the most straightforward method for dictionary comparison. It returns True if two dictionaries contain the exact same items, regardless of their order. This is because Python dictionaries, by their nature, don't consider insertion order when checking for equality.
The comparison evaluates to True only if both dictionaries have:
- The same set of keys.
- Identical values for each corresponding key.
In the example, dict1 == dict2 is True because they meet these criteria. Conversely, dict1 == dict3 is False since the value for the key 'b' differs between them.
Basic comparison techniques
Beyond the == operator, you can check for object identity with is, compare entries directly with items(), or see if one dictionary is a subset of another.
Comparing dictionary identity with the is operator
dict1 = {'a': 1, 'b': 2}
dict2 = {'a': 1, 'b': 2}
dict3 = dict1
print(dict1 is dict2) # Different objects with same content
print(dict1 is dict3) # Same object (reference)--OUTPUT--False
True
The is operator checks for object identity, not content equality. It verifies if two variables point to the exact same object in memory. This is a stricter comparison than ==, which only evaluates the contents.
- Since
dict1anddict2are created independently, they are distinct objects, even with identical key-value pairs. This is whydict1 is dict2returnsFalse. - In contrast,
dict3is assigned directly fromdict1. It acts as a reference, pointing to the very same object, sodict1 is dict3evaluates toTrue.
Comparing dictionary entries with items()
dict1 = {'a': 1, 'b': 2}
dict2 = {'a': 1, 'c': 3}
common_items = set(dict1.items()) & set(dict2.items())
diff_items = set(dict1.items()) - set(dict2.items())
print(f"Common items: {common_items}")
print(f"Items in dict1 but not in dict2: {diff_items}")--OUTPUT--Common items: {('a', 1)}
Items in dict1 but not in dict2: {('b', 2)}
You can compare dictionaries at a more granular level by converting their key-value pairs into sets. The items() method returns a view of the dictionary's pairs, which you can then pass to set(). This approach unlocks powerful set operations for finding commonalities and differences, building on the fundamentals of accessing dictionary values.
- The intersection operator (
&) identifies items present in both dictionaries. - The difference operator (
-) finds items that exist in the first dictionary but not the second.
Checking if one dictionary is a subset of another
dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'a': 1, 'b': 2}
is_subset = all(item in dict1.items() for item in dict2.items())
print(f"dict2 is a subset of dict1: {is_subset}")
print(f"Keys in dict1 not in dict2: {dict1.keys() - dict2.keys()}")--OUTPUT--dict2 is a subset of dict1: True
Keys in dict1 not in dict2: {'c'}
To see if one dictionary is a subset of another, you can check if all its items exist in the larger dictionary. The expression all(item in dict1.items() for item in dict2.items()) iterates through each key-value pair in dict2 and confirms its presence in dict1. The all() function ensures this is true for every item, making it a reliable subset test.
- This is useful for verifying that a smaller dataset is fully contained within a larger one.
- You can also find keys that are unique to one dictionary using set operations, like
dict1.keys() - dict2.keys(). Once you identify common elements, you might want to explore merging dictionaries to combine their data.
Advanced comparison methods
When simple equality checks aren't enough, you can turn to more powerful methods for handling nested data, specific keys, and custom comparison rules.
Deep comparison for nested dictionaries
import json
dict1 = {'a': 1, 'b': {'x': 1, 'y': 2}}
dict2 = {'a': 1, 'b': {'y': 2, 'x': 1}} # Same content, different order
dict3 = {'b': {'x': 1, 'y': 2}, 'a': 1} # Same content, different order
print(json.dumps(dict1) == json.dumps(dict2)) # String comparison preserves order
print(dict1 == dict3) # Dictionary comparison ignores order--OUTPUT--False
True
When dictionaries contain other dictionaries, the standard == operator handles the comparison recursively. It digs into nested structures to check for content equality while ignoring key order at every level. This is why dict1 == dict3 correctly evaluates to True, as their contents are identical.
- Be careful with methods that don't respect dictionary structure, like converting to a string with
json.dumps(). - The expression
json.dumps(dict1) == json.dumps(dict2)returnsFalsebecause string comparison is order-sensitive, and the keys in the nested dictionaries are in a different order.
Comparing specific dictionary keys
dict1 = {'name': 'Alice', 'age': 30, 'city': 'New York'}
dict2 = {'name': 'Alice', 'age': 25, 'country': 'USA'}
keys_to_compare = ['name', 'age']
match = all(dict1.get(k) == dict2.get(k) for k in keys_to_compare)
print(f"Dictionaries match on specified keys: {match}")--OUTPUT--Dictionaries match on specified keys: False
Sometimes you only need to compare a subset of keys. You can do this by iterating through a predefined list and using a generator expression with the all() function. This approach checks if the values for each specified key match across both dictionaries.
- Using
dict.get(k)is a safe way to retrieve values because it returnsNoneif a key is missing, preventing aKeyError. - In the example, the comparison returns
Falsebecause the values for the'age'key don't match, causingall()to stop and return its result immediately.
Custom comparison with tolerance using dictionary comprehension
dict1 = {'a': 10, 'b': 20, 'c': 30}
dict2 = {'a': 11, 'b': 19, 'c': 31}
# Check if values are within ±2 of each other
tolerance_match = all(abs(dict1[k] - dict2[k]) <= 2 for k in dict1 if k in dict2)
print(f"Values match within tolerance: {tolerance_match}")--OUTPUT--Values match within tolerance: True
When dealing with numerical data, an exact match isn't always what you need. A dictionary comprehension combined with the all() function lets you define custom comparison rules, like a tolerance for small differences.
- The expression iterates through keys common to both dictionaries, thanks to the
if k in dict2check. - For each shared key,
abs(dict1[k] - dict2[k]) <= 2calculates the absolute difference and confirms it's within the allowed tolerance. all()returnsTrueonly if every comparison meets this condition.
Move faster with Replit
Replit is an AI-powered development platform that comes with all Python dependencies pre-installed, so you can skip setup and start coding instantly. This helps you move from learning individual techniques to building complete applications.
Instead of piecing together comparison methods, you can describe the app you want to build and Agent 4 will take it from idea to working product—handling the code, databases, APIs, and deployment. For example, you could build:
- A configuration validator that compares a user's settings against a master template, ensuring all required keys are present and values match.
- A data reconciliation tool that finds differences between two large datasets, flagging mismatched values or keys that exist in one but not the other.
- A system monitor that compares real-time performance metrics against a baseline dictionary, triggering an alert if any value deviates beyond a set tolerance.
Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.
Common errors and challenges
Comparing dictionaries can lead to errors from missing keys, complex data types, or confusion between shallow and deep copies.
- Avoiding
KeyErrorwhen comparing dictionaries with missing keys: AKeyErroris a frequent stumbling block that occurs when you try to access a key that doesn't exist. To prevent this, use theget()method, which safely returnsNoneif a key is missing, or compare key sets first to identify differences before accessing values. - Handling
TypeErrorwhen comparing complex dictionary values: You might see aTypeErrorif your dictionaries contain values that can't be compared, like custom objects. Python's==operator doesn't automatically know how to check for equality, so you need to define the logic yourself by implementing the__eq__method in your custom class. - Shallow vs. deep copy confusion in dictionary comparisons: A shallow copy only duplicates the top-level dictionary, not nested objects. Modifying a nested list or dictionary in the copy will also change the original, leading to unexpected comparison results. A deep copy creates fully independent duplicates, preventing this common source of bugs.
Avoiding KeyError when comparing dictionaries with missing keys
A KeyError is a common roadblock when comparing dictionaries that don't share the same keys. It's triggered when your code tries to access a key that's missing from one of them, causing an immediate crash. The following example demonstrates this scenario.
def compare_values(dict1, dict2, key):
return dict1[key] == dict2[key]
user1 = {'name': 'Alice', 'email': 'alice@example.com'}
user2 = {'name': 'Bob', 'phone': '555-1234'}
print(compare_values(user1, user2, 'email')) # KeyError: 'email'
The function compare_values fails because it tries to access the 'email' key, which doesn't exist in the user2 dictionary. This triggers the KeyError. The corrected approach below shows how to handle missing keys gracefully.
def compare_values(dict1, dict2, key):
return key in dict1 and key in dict2 and dict1[key] == dict2[key]
user1 = {'name': 'Alice', 'email': 'alice@example.com'}
user2 = {'name': 'Bob', 'phone': '555-1234'}
print(compare_values(user1, user2, 'email')) # False
The solution avoids a KeyError by first confirming the key exists in both dictionaries. The expression key in dict1 and key in dict2 uses short-circuiting—if the key is missing from the first dictionary, the check stops and returns False immediately. For more comprehensive strategies on solving KeyError issues, consider defensive programming techniques.
This prevents the code from ever attempting the risky value lookup on a missing key. It’s a robust way to compare values when you can't guarantee your dictionaries will have the same structure.
Handling TypeError when comparing complex dictionary values
A TypeError often appears when your dictionary values have incompatible types. You can't, for instance, find the intersection of a list and a set using the & operator, as they don't support this operation together. The following code demonstrates this exact problem.
user1 = {'name': 'Alice', 'tags': ['python', 'data']}
user2 = {'name': 'Bob', 'tags': {'python', 'web'}}
common_tags = user1['tags'] & user2['tags'] # TypeError: unsupported operand
print(f"Common tags: {common_tags}")
The & operator expects two sets but receives a list from user1['tags'] and a set from user2['tags']. This mismatch is what triggers the TypeError. The corrected approach below handles this incompatibility by ensuring the types match.
user1 = {'name': 'Alice', 'tags': ['python', 'data']}
user2 = {'name': 'Bob', 'tags': {'python', 'web'}}
common_tags = set(user1['tags']) & set(user2['tags'])
print(f"Common tags: {common_tags}") # {'python'}
The solution works by standardizing the data types before the comparison. By converting both tags values to sets with set(), you ensure they are compatible with the intersection operator (&). This simple type conversion resolves the TypeError.
This error often appears when dictionaries store different collection types—like lists and sets—and you try to perform an operation that isn't supported by both.
Shallow vs. deep copy confusion in dictionary comparisons
The difference between a shallow and deep copy is a common source of bugs. A shallow copy, created with methods like copy(), only duplicates the top-level dictionary. Nested objects are shared, not copied, which can lead to unexpected modifications. Understanding the nuances of copying dictionaries in Python is essential for avoiding these pitfalls.
This behavior causes confusing comparison results, as a change in the copy also alters the original. The code below shows how a shallow copy can silently modify the original dictionary, leading to a misleading True result when they are compared.
original = {'user': {'name': 'Alice', 'score': 85}}
copy = original.copy() # Shallow copy
copy['user']['score'] = 90
print(original == copy) # True, but original was modified!
print(original) # {'user': {'name': 'Alice', 'score': 90}}
The copy() method only duplicates the top level. When copy['user']['score'] is updated, the original dictionary changes too because the nested user object is a shared reference. See how to create a true duplicate below.
import copy
original = {'user': {'name': 'Alice', 'score': 85}}
deep_copy = copy.deepcopy(original) # Deep copy
deep_copy['user']['score'] = 90
print(original == deep_copy) # False
print(original) # {'user': {'name': 'Alice', 'score': 85}}
The fix is to use copy.deepcopy(), which creates a fully independent duplicate of the dictionary, including all nested objects. Unlike a shallow copy, modifying the deep_copy doesn't affect the original at all. This is why the comparison now correctly returns False. Always reach for a deep copy when you're working with nested data structures and need to ensure the original dictionary remains unchanged after you modify its copy.
Real-world applications
Moving past common errors, you can now apply these comparison techniques to practical tasks like tracking user data and visualizing configuration differences with vibe coding.
Tracking user profile changes with dictionary comparison
You can efficiently track updates to user data, like profile information, by comparing old and new dictionary states to isolate what has changed with AI coding.
old_profile = {'name': 'John', 'bio': 'Python developer', 'followers': 120}
new_profile = {'name': 'John', 'bio': 'Python & JS developer', 'followers': 145}
keys_to_check = set(old_profile) | set(new_profile)
changes = {k: (old_profile.get(k), new_profile.get(k)) for k in keys_to_check
if old_profile.get(k) != new_profile.get(k)}
print(f"Profile changes: {changes}")
This snippet efficiently identifies what's changed between two dictionaries. It creates a log of modifications by comparing an old profile state to a new one.
- First, it gathers all unique keys from both dictionaries into a single set using the union operator (
|). This ensures you check every key, even if it was added or removed. - A dictionary comprehension then iterates through these keys, using
get()to safely pull values without causing an error if a key is missing. - It builds a new
changesdictionary, storing only the keys where the values have changed.
Visualizing dictionary differences with the difflib module
For a more visual, line-by-line comparison, Python's built-in difflib module can generate a human-readable diff that highlights changes, additions, and deletions between two dictionaries.
import difflib
config1 = {'debug': True, 'api_url': 'api.example.com', 'timeout': 30}
config2 = {'debug': False, 'api_url': 'api.example.com', 'retry': 3}
config1_items = [f"{k}: {v}" for k, v in sorted(config1.items())]
config2_items = [f"{k}: {v}" for k, v in sorted(config2.items())]
diff = difflib.ndiff(config1_items, config2_items)
print('\n'.join(list(diff)))
This code uses Python's difflib module to find the differences between two dictionaries. It first prepares the data by converting each dictionary's items into a sorted list of strings. This step is crucial because the comparison function, difflib.ndiff(), operates on sequences and needs a consistent order to work correctly. For more control over the ordering process, see techniques for sorting dictionary keys.
- The
ndiff()function then computes a delta between the two prepared lists. - The output is a generator of strings that represents the transformation from the first configuration to the second.
Get started with Replit
Turn these comparison techniques into a real tool. Tell Replit Agent to build a "config file diff tool" or a "data validation script that flags mismatches between two datasets."
Replit Agent will write the code, test for errors, and deploy your application for you. Start building with Replit.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.



