How to update a dictionary in Python

Learn how to update a Python dictionary with various methods. Discover tips, real-world uses, and how to debug common errors.

How to update a dictionary in Python
Published on: 
Fri
Feb 13, 2026
Updated on: 
Tue
Feb 24, 2026
The Replit Team Logo Image
The Replit Team

To manage dynamic data, you must know how to update Python dictionaries. This core skill lets you modify key-value pairs efficiently for many programming tasks.

You'll learn several update methods, from the update() function to direct assignment. You'll also find practical tips, real-world applications, and advice to debug your code.

Basic key assignment to update a dictionary

student = {'name': 'John', 'age': 21}
student['age'] = 22 # Update existing key
student['grade'] = 'A' # Add new key-value pair
print(student)--OUTPUT--{'name': 'John', 'age': 22, 'grade': 'A'}

Direct key assignment is the most fundamental way to update a Python dictionary. This method uses the assignment operator (=) to either modify an existing entry or add a new one. It's a simple and readable approach for targeted changes.

  • Updating: When you assign a value to an existing key, like student['age'] = 22, you overwrite its previous value.
  • Adding: If the key doesn't exist, as with student['grade'] = 'A', Python creates a new key-value pair.

This dual-purpose behavior makes direct assignment incredibly versatile for quick modifications without needing special functions.

Common dictionary update methods

Moving beyond simple key assignment, you can use more advanced techniques like the update() method and dictionary comprehensions for bulk or conditional changes.

Using the update() method

user_info = {'name': 'Alice', 'email': 'alice@example.com'}
new_data = {'phone': '555-1234', 'email': 'alice.new@example.com'}
user_info.update(new_data)
print(user_info)--OUTPUT--{'name': 'Alice', 'email': 'alice.new@example.com', 'phone': '555-1234'}

The update() method efficiently merges one dictionary into another. It modifies the original dictionary in place by adding or overwriting key-value pairs from the second dictionary.

  • If a key already exists, like 'email', its value is updated with the new one.
  • If a key is new, like 'phone', the key-value pair is added to the dictionary.

Using dictionary comprehension for conditional updates

scores = {'math': 85, 'science': 92, 'history': 78}
scores = {subject: (score + 5 if score < 90 else score) for subject, score in scores.items()}
print(scores)--OUTPUT--{'math': 90, 'science': 92, 'history': 83}

Dictionary comprehensions let you create a new dictionary from an existing one in a single, readable line. They're perfect for applying conditional logic to each key-value pair without writing a full loop.

  • The expression iterates through the dictionary using scores.items().
  • A conditional statement—score + 5 if score < 90 else score—checks each value. It adds 5 to any score below 90 and leaves the others as they are.

This method doesn't modify the dictionary in place. Instead, it builds a completely new dictionary that you then assign back to the original variable.

Using the .get() method for safe updates

inventory = {'apples': 10, 'bananas': 15}
fruit = 'apples'
inventory[fruit] = inventory.get(fruit, 0) + 5
print(inventory)--OUTPUT--{'apples': 15, 'bananas': 15}

The get() method offers a safe way to update values by preventing KeyError exceptions. It retrieves a key's value, but if the key doesn't exist, it'll return a default value you provide instead of crashing your program. This is especially useful for incrementing counters or values that might not be initialized yet.

  • In the example, inventory.get(fruit, 0) looks for the fruit key.
  • Since 'apples' exists, it returns 10, and the new value becomes 15.
  • If the fruit wasn't in the inventory, get() would return 0, safely setting its new count to 5.

Advanced dictionary update techniques

To handle updates with even greater safety and automation, you can leverage advanced techniques like the ** operator, collections.defaultdict, and dict.setdefault().

Using dictionary unpacking with ** operator

defaults = {'timeout': 30, 'retry': 3, 'logging': False}
user_config = {'timeout': 60, 'verbose': True}
final_config = {**defaults, **user_config}
print(final_config)--OUTPUT--{'timeout': 60, 'retry': 3, 'logging': False, 'verbose': True}

You can merge dictionaries using the ** unpacking operator. This technique creates a new dictionary by combining the key-value pairs from others, which is perfect for setting up configurations.

  • The expression {**defaults, **user_config} unpacks both dictionaries into a new one.
  • If a key like 'timeout' appears in both, the value from the right-most dictionary (user_config) is used.
  • New keys like 'verbose' are simply added.

Unlike the update() method, this approach doesn't alter the original dictionaries. It produces a completely new one.

Using collections.defaultdict for automatic initialization

from collections import defaultdict
word_count = defaultdict(int)
for word in ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']:
word_count[word] += 1
print(dict(word_count))--OUTPUT--{'apple': 3, 'banana': 2, 'orange': 1}

The defaultdict from the collections module simplifies counting and grouping tasks by automatically handling missing keys. When you create a defaultdict(int), you're telling it to use 0 as the default value for any new key it encounters.

  • This lets you directly increment a counter like word_count[word] += 1 without first checking if the key exists.
  • It’s a clean way to avoid a KeyError when building frequency maps or accumulating values, making your code more concise.

Using dict.setdefault() to update with defaults

contacts = {'John': ['555-1234']}
name = 'Alice'
contacts.setdefault(name, []).append('555-5678')
contacts.setdefault('John', []).append('555-8765')
print(contacts)--OUTPUT--{'John': ['555-1234', '555-8765'], 'Alice': ['555-5678']}

The dict.setdefault() method provides a concise way to get a key's value or initialize it with a default if the key isn't found. It’s perfect for managing collections like lists within a dictionary because it combines checking and setting into one step.

  • When you call contacts.setdefault('Alice', []), the key 'Alice' is new, so an empty list is created and assigned. The method returns this new list, letting you immediately .append() a value.
  • For an existing key like 'John', setdefault() just returns the current list, and the new phone number is appended to it.

Move faster with Replit

Replit is an AI-powered development platform that transforms natural language into working applications. Describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.

For the dictionary update techniques we've explored, Replit Agent can turn them into production tools:

  • Build a configuration manager that merges default and user-specific settings using the ** operator.
  • Create a real-time analytics dashboard that uses defaultdict to track user engagement events without raising a KeyError.
  • Deploy a contact management system that groups multiple phone numbers under a single contact with setdefault().

Describe your app idea, and Replit Agent writes the code, tests it, and fixes issues automatically, all in your browser.

Common errors and challenges

Even with the right methods, you might encounter a few common roadblocks, from using invalid keys to accidentally modifying the wrong dictionary.

Forgetting that dictionary keys must be hashable

One of the first rules you'll learn is that dictionary keys must be hashable. This means their value can't change during their lifetime. Immutable types like strings, numbers, and tuples work perfectly as keys because they can be reliably converted into a unique identifier, or hash.

  • On the other hand, mutable types like lists or other dictionaries can't be used as keys.
  • If you try, Python will raise a TypeError because their contents can change, making it impossible to guarantee a stable hash.

Avoiding KeyError when accessing nonexistent keys

A KeyError is a frequent stumbling block that occurs when you try to access a key that doesn't exist. Using direct bracket notation like my_dict['nonexistent_key'] will immediately stop your program if the key isn't found.

While this behavior is sometimes useful for catching mistakes, it can also cause unexpected crashes. You can prevent this by using the .get() method to provide a default value or by using a defaultdict for automatic initialization.

Common pitfall with dictionary references

It's easy to assume that assigning a dictionary to a new variable creates a copy, but it doesn't. When you write new_dict = old_dict, both variables point to the exact same dictionary in memory. Any change you make to new_dict will also appear in old_dict, which can lead to confusing bugs.

To create an independent copy, you need to be explicit. Use the .copy() method or dictionary unpacking with the ** operator to create a new dictionary that you can modify without affecting the original.

Forgetting that dictionary keys must be hashable

This rule trips up many developers who try to use a mutable type, like a list, as a key. Since a list's contents can change, it isn't hashable, and Python will raise a TypeError. The following code demonstrates this common error.

# Trying to use a list as a dictionary key
coordinates = {}
coordinates[[1, 2]] = "Point A" # This will raise TypeError
print(coordinates)

This code breaks because you're trying to use a list, [1, 2], as a dictionary key. Since lists are mutable, Python can't create the permanent hash it needs. The fix is to use an immutable type instead. See how it's done below.

# Using a tuple (immutable) instead of a list
coordinates = {}
coordinates[(1, 2)] = "Point A" # Works correctly
print(coordinates)

The fix is to replace the mutable list with an immutable tuple. Since tuples can't be changed after they're created, Python can reliably hash them. By changing [1, 2] to (1, 2), the key becomes valid, and the code runs without a TypeError. This is a common issue when working with complex data structures as keys, so always reach for an immutable type like a tuple or string when you need a multi-part key.

Avoiding KeyError when accessing nonexistent keys

Directly accessing a key that might not exist is a recipe for a KeyError. This error immediately stops your script, which is especially problematic when processing data from external sources where keys aren't guaranteed. The code below shows this common pitfall.

user_data = {'name': 'John', 'email': 'john@example.com'}
age = user_data['age'] # This raises KeyError: 'age'
print(f"User is {age} years old")

Accessing user_data['age'] fails because the key 'age' isn't in the dictionary, which triggers a KeyError and stops the script. The following example demonstrates a safer way to handle potentially missing keys.

user_data = {'name': 'John', 'email': 'john@example.com'}
age = user_data.get('age', 'unknown') # Safe access with default
print(f"User is {age} years old")

The fix uses the get() method to safely access the dictionary. By calling user_data.get('age', 'unknown'), the code looks for the 'age' key. Since it doesn't find it, the method returns the default value, 'unknown', instead of raising an error. This approach is essential when you're processing data where some keys might be optional or missing, ensuring your application doesn't crash unexpectedly.

Common pitfall with dictionary references

A common pitfall is thinking an assignment like backup = original creates a new dictionary. It doesn't—it only creates a reference, so both variables point to the same data. This leads to bugs where one change affects both, as the code below demonstrates.

original = {'settings': {'theme': 'dark'}}
backup = original # Creates a reference, not a copy
backup['settings']['theme'] = 'light' # Changes both dictionaries
print(original) # Shows {'settings': {'theme': 'light'}}

Because backup is just another name for the original dictionary, modifying the theme through backup also alters original. This side effect is a classic bug when you're working with a reference instead of a true copy. See how to fix it below.

import copy
original = {'settings': {'theme': 'dark'}}
backup = copy.deepcopy(original) # Creates a true copy
backup['settings']['theme'] = 'light' # Only changes backup
print(original) # Shows {'settings': {'theme': 'dark'}}

The fix is to create a true, independent copy using copy.deepcopy(). This function recursively duplicates the entire dictionary, including any nested data structures inside it. As a result, modifying the backup dictionary won't affect the original at all. It's a vital technique to use whenever you're handling nested data, like configurations or user profiles, and need to preserve the original while you work on a separate version.

Real-world applications

Knowing how to sidestep common errors lets you confidently apply these update methods to powerful, real-world applications.

Managing app settings with the ** unpacking operator

Many applications rely on a configuration system that combines default settings with user-specific overrides. The ** unpacking operator is perfect for this, letting you merge two dictionaries into a new one where the second dictionary's values overwrite the first's.

For example, you can define a default_config dictionary and a user_config dictionary. By creating a final_config with {**default_config, **user_config}, you get a single, consolidated set of settings where the user's choices take priority. This approach is clean, readable, and safely creates a new object without altering the original sources.

Creating a word frequency analyzer with defaultdict

When you need to count items, like analyzing word frequencies in a document, defaultdict is a game-changer. Without it, you'd have to write extra code to check if a word is already in your dictionary before incrementing its count.

By using a defaultdict(int), you tell Python to automatically create an entry with a value of 0 the first time a new word is encountered. This lets you simply use word_counts[word] += 1 for every word, making your code for tasks like data analysis or logging much more concise and eliminating the risk of a KeyError.

Managing app settings with the ** unpacking operator

The ** operator provides a clean way to build a final configuration by unpacking default_settings and layering user_settings on top.

default_settings = {'theme': 'light', 'notifications': True, 'language': 'en'}
user_settings = {'theme': 'dark'}
active_settings = {**default_settings, **user_settings}
print(active_settings)

# User changes a setting
user_settings['notifications'] = False
active_settings = {**default_settings, **user_settings}
print(active_settings)

This example shows how the ** operator merges dictionaries into a new one. The order is key, as values from the right-most dictionary (user_settings) overwrite any matching keys from the left.

  • First, active_settings is created, and the 'theme' from user_settings overrides the default.
  • After user_settings is updated with a new notification preference, the merge is run again. This creates a brand-new active_settings dictionary, showing how you can dynamically rebuild configurations to reflect changes.

Creating a word frequency analyzer with defaultdict

A defaultdict streamlines text analysis by letting you loop through words and increment their counts directly, as it automatically handles any word the first time it appears.

from collections import defaultdict

text = "Python is amazing Python is a great language to learn"
words = text.lower().split()
frequency = defaultdict(int)
for word in words:
frequency[word] += 1

print(dict(frequency))

This snippet tallies word occurrences in a string. It first normalizes the text by converting it to lowercase with .lower() and splitting it into a list of words using .split(). This ensures 'Python' and 'python' are counted as the same word.

A defaultdict(int) is then initialized. This special dictionary uses int()—which returns 0—as a factory for missing keys. As the code loops through the words:

  • The line frequency[word] += 1 increments the count for each word.
  • This works even for new words because the defaultdict provides a default value of 0 on the first access.

Finally, the result is converted to a standard dictionary for display.

Get started with Replit

Turn these techniques into a real tool. Describe what you want to build, like "a config manager that merges default and user settings" or "a live dashboard that tracks user actions with a defaultdict".

Replit Agent will write the code, test for errors, and deploy your app from a single prompt. Start building with Replit.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started for free

Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.