Table of contents
Implement code functionality

How to compare two dictionaries in Python

May 30, 2025
 ・ by  
Claude and the Anthropic Team
Table of contents
H2 Link Template
Try Claude

Comparing Python dictionaries efficiently helps developers validate data consistency, track state changes, and identify discrepancies between datasets. Python provides multiple built-in methods and operators to compare dictionary contents and structures.

This guide covers essential comparison techniques, practical tips, and real-world applications, with code examples created using Claude, an AI assistant built by Anthropic.

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
True
False

The equality operator == compares dictionary contents without considering the order of key-value pairs. This behavior makes it particularly useful when validating data consistency across different sources where the insertion sequence might vary.

The example demonstrates two key aspects of dictionary comparison:

  • Order-independence: dict1 and dict2 contain identical key-value pairs in different orders, yet evaluate as equal
  • Value sensitivity: dict1 and dict3 share the same keys but differ in one value, resulting in inequality

Basic comparison techniques

Beyond basic equality checks, Python offers specialized dictionary comparison methods like is, items(), and subset validation to handle more nuanced data validation scenarios.

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)
False
True

The is operator checks if two dictionaries reference the exact same object in memory rather than comparing their contents. When you create two separate dictionaries with identical key-value pairs like dict1 and dict2, they occupy different memory locations and return False when compared with is.

However, when you assign dict3 = dict1, both variables point to the same dictionary object in memory. This creates a reference rather than a copy. That's why dict1 is dict3 returns True.

  • Use is to check dictionary identity when you need to verify if two variables reference the same object
  • Use == instead when you want to compare dictionary contents regardless of memory location

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}")
Common items: {('a', 1)}
Items in dict1 but not in dict2: {('b', 2)}

The items() method converts dictionary key-value pairs into a set-compatible format, enabling powerful set operations for comparison. Converting dictionaries to sets unlocks efficient ways to find common elements and differences between them.

  • The & operator identifies shared key-value pairs between dictionaries, stored in common_items
  • The - operator finds key-value pairs unique to the first dictionary, stored in diff_items
  • This approach proves especially useful when comparing complex dictionaries or tracking data changes over time

In the example, both dictionaries share the pair ('a', 1). The pair ('b', 2) exists only in dict1, making it appear in the difference set.

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()}")
dict2 is a subset of dict1: True
Keys in dict1 not in dict2: {'c'}

The all() function elegantly checks if every key-value pair in dict2 exists within dict1. When all pairs match, we consider dict2 a subset of dict1.

  • The generator expression item in dict1.items() for item in dict2.items() compares each pair efficiently without creating intermediate lists
  • The set operation dict1.keys() - dict2.keys() reveals which keys exist exclusively in dict1
  • This pattern proves invaluable when validating data completeness or verifying that one dictionary contains all required entries from another

In the example, dict2 qualifies as a subset because its key-value pairs 'a': 1 and 'b': 2 exist in dict1. Meanwhile, 'c' appears only in dict1.

Advanced comparison methods

Building on the foundational comparison techniques, Python offers sophisticated methods to handle nested data structures, selective key validation, and flexible numeric comparisons with customizable thresholds.

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
False
True

When comparing nested dictionaries, Python's standard equality operator == treats nested structures intelligently. It recursively compares all levels while maintaining order-independence, as shown by dict1 == dict3 returning True.

The json.dumps() method offers a different approach by converting dictionaries to JSON strings. Since string comparison is order-sensitive, json.dumps(dict1) == json.dumps(dict2) returns False despite containing identical data.

  • Use == when you need to compare nested dictionary contents regardless of order
  • Choose json.dumps() comparison when order matters or when you need to verify exact structural matches
  • Both methods handle nested structures automatically without requiring manual recursion

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}")
Dictionaries match on specified keys: False

Selective key comparison lets you validate specific dictionary fields while ignoring others. The get() method safely retrieves values even if a key doesn't exist, returning None instead of raising an error.

  • The keys_to_compare list defines which fields to check—in this case only 'name' and 'age'
  • The all() function with a generator expression efficiently checks if every specified key matches between dictionaries
  • The comparison returns False because while the names match, the ages differ (30 vs 25)

This pattern proves especially useful when comparing data records where only certain fields matter for validation. The different city and country values don't affect the result since they aren't in keys_to_compare.

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}")
Values match within tolerance: True

Custom tolerance comparison enables flexible matching between dictionary values that are close but not exactly equal. The abs() function calculates the absolute difference between corresponding values, while the all() function ensures every pair falls within the specified tolerance of ±2.

  • The generator expression abs(dict1[k] - dict2[k]) <= 2 checks if the difference between values is 2 or less
  • The condition k in dict2 safely handles cases where keys exist in one dictionary but not the other
  • This approach proves valuable when comparing numerical data that may have minor variations due to rounding or measurement differences

In the example, all values in dict2 differ from dict1 by only 1, so the comparison returns True. This technique offers more flexibility than strict equality checks when working with real-world data.

Get unstuck faster with Claude

Claude is an AI assistant created by Anthropic that excels at helping developers write, debug, and understand code. It combines deep technical knowledge with natural conversation to provide clear, actionable guidance.

While working with complex dictionary comparisons or any other Python challenges, Claude serves as your AI coding mentor. It can explain concepts like nested dictionary traversal, suggest optimal comparison approaches, and help troubleshoot edge cases in your implementation.

Start accelerating your Python development today. Sign up for free at Claude.ai to get personalized assistance with code reviews, debugging sessions, and best practice recommendations.

Some real-world applications

Building on the advanced comparison techniques we've explored, dictionary comparison solves real challenges in production environments—from tracking user behavior to visualizing data changes.

Tracking user profile changes with dictionary comparison

Dictionary comparison enables precise tracking of user profile updates by identifying changed fields, modified values, and new or removed attributes in social platforms and content management systems.

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 code efficiently detects changes between two profile dictionaries. The set() function converts dictionary keys to sets while the | operator combines them into a unified set of all possible keys. A dictionary comprehension then creates changes, which stores only the modified values as tuples.

The get() method safely handles missing keys by returning None instead of raising errors. The comparison runs only when values differ between profiles.

  • The output shows both the old and new values for each changed field
  • The code gracefully handles cases where keys exist in one profile but not the other
  • This approach scales well for dictionaries of any size

Visualizing dictionary differences with the difflib module

Python's difflib module provides a powerful way to visualize differences between dictionaries by converting them into human-readable, line-by-line comparisons that highlight changes, additions, and removals.

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)))

The code demonstrates a practical way to compare two configuration dictionaries and visualize their differences. The difflib module's ndiff() function analyzes text-based differences between sequences. First, the code converts each dictionary into a sorted list of formatted strings using list comprehension with f"{k}: {v}".

  • The sorted() function ensures consistent ordering of dictionary items
  • The join() method with \n creates a clean, line-by-line output
  • The resulting diff shows added, removed, or modified configuration values with special markers

This approach makes it easy to spot configuration changes at a glance. It's particularly useful when comparing complex dictionaries or tracking changes in configuration files.

Common errors and challenges

Dictionary comparison in Python requires careful handling of missing keys, complex data types, and copy operations to avoid common runtime errors and unexpected behavior.

Avoiding KeyError when comparing dictionaries with missing keys

Direct dictionary key access with square bracket notation raises a KeyError when a key doesn't exist. This common pitfall occurs when comparing dictionaries with different key sets. The code below demonstrates how accessing a missing key interrupts program execution.

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 compare_values() function directly accesses dictionary keys without checking their existence first. When user2 lacks the 'email' key, Python raises a KeyError. The code below demonstrates a safer approach to handle missing keys.

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 improved code checks for key existence before attempting comparison. By using the in operator and logical AND (and), the function first verifies that both dictionaries contain the key. Only then does it compare the values.

  • Always verify key existence when comparing dictionaries with potentially different structures
  • The get() method offers an alternative approach by returning None for missing keys
  • This pattern prevents runtime errors in data validation scenarios where dictionary contents may vary

Watch for this issue when working with user input, API responses, or any data source where dictionary structure isn't guaranteed consistent.

Handling TypeError when comparing complex dictionary values

Comparing dictionary values containing different data types like lists and sets can trigger a TypeError. This common issue occurs when applying set operations between incompatible collection types. The code below demonstrates how mixing lists and sets leads to runtime errors.

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 error occurs because the & operator can't directly compare a list and a set. Lists don't support set operations. The code attempts to find common elements between two different collection types. Let's examine the corrected implementation below.

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'}

Converting both collections to sets before comparison solves the TypeError. The set() function transforms any iterable into a set, enabling the use of set operations like & to find common elements. This approach works because sets only contain unique values and support efficient intersection operations.

  • Watch for this error when comparing dictionary values containing different collection types
  • Common scenarios include processing user tags, categories, or any nested data structures
  • Always verify the data types of nested collections before applying set operations

The solution proves especially useful when dealing with data from multiple sources where collection types might vary. Converting to sets standardizes the comparison process.

Shallow vs. deep copy confusion in dictionary comparisons

Python's shallow copy mechanism can lead to unexpected behavior when comparing nested dictionaries. The copy() method only creates a surface-level duplicate, leaving nested objects sharing the same memory reference. The code below demonstrates how modifying a nested value affects both the original and copied dictionaries.

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 shallow copy creates a new dictionary that still references the same nested user dictionary in memory. When modifying nested values, both dictionaries change because they share that reference. Let's examine the corrected implementation using deep copy.

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 copy.deepcopy() function creates a completely independent copy of a dictionary and all its nested objects. Unlike shallow copying with .copy(), deep copying ensures that modifying nested values in the copy won't affect the original dictionary.

  • Deep copying recursively duplicates every object in the dictionary hierarchy
  • Each nested dictionary gets its own memory space
  • Changes to nested values remain isolated between copies

Watch for this issue when working with dictionaries containing nested data structures like lists, dictionaries, or custom objects. The problem commonly surfaces in data processing pipelines where you need to preserve the original data while making modifications to a copy.

Learning or leveling up? Use Claude

Claude stands out as a sophisticated AI companion that transforms complex programming concepts into clear, actionable insights. Its deep understanding of Python and software development patterns makes it an invaluable resource for developers seeking to master dictionary operations and data structure manipulation.

Here are some ways Claude can assist with dictionary comparisons:

  • Debug comparison logic: Ask "Why does my dictionary comparison return unexpected results?" and Claude will analyze your code to identify common pitfalls like shallow copying or missing key errors
  • Optimize performance: Ask "How can I make my dictionary comparison more efficient?" and Claude will suggest techniques like using set operations or generator expressions
  • Handle edge cases: Ask "What's the best way to compare dictionaries with missing keys?" and Claude will demonstrate safe comparison patterns using get() or key existence checks
  • Explore alternatives: Ask "What are different ways to compare nested dictionaries?" and Claude will explain approaches from basic equality checks to recursive comparison methods
  • Implement features: Ask "How do I track changes between two dictionaries?" and Claude will help you build a solution that identifies added, modified, and removed key-value pairs

Experience personalized coding assistance today by signing up for free at Claude.ai.

For a more integrated development experience, Claude Code brings AI-powered assistance directly to your terminal, enabling seamless collaboration while you write and refactor Python code.

FAQs

Additional Resources

How to use booleans in Python

2025-05-30
14 min
 read
Read more

How to use 'e' in Python

2025-05-30
14 min
 read
Read more

How to convert a string to a list in Python

2025-05-30
14 min
 read
Read more

Leading companies build with Claude

ReplitCognitionGithub CopilotCursorSourcegraph
Try Claude
Get API Access
Copy
Expand