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 in your code.

How to update a dictionary in Python
Published on: 
Fri
Feb 13, 2026
Updated on: 
Mon
Apr 13, 2026
The Replit Team

Python dictionaries are versatile data structures that often require modification after creation. Python provides several built-in methods to update dictionaries efficiently, each suited for different scenarios.

In this guide, you'll explore methods for updating dictionaries, including the update() method and dictionary unpacking. You'll find practical tips, real-world applications, and debugging advice to help you select the right approach.

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

The most direct way to modify a dictionary is by using key assignment with square brackets. This approach is powerful because it handles both updating an existing key and adding a new one. When you use the syntax dictionary['key'] = value, Python first checks if the key exists. If it does, the existing value is replaced; if not, a new key-value pair is created.

In the example, student['age'] = 22 targets an existing key, 'age', and overwrites its value. Conversely, student['grade'] = 'A' introduces a new key-value pair since 'grade' isn't already in the dictionary. This method is perfect for targeted, single-key modifications.

Common dictionary update methods

Beyond making single-key changes, Python offers more advanced tools for bulk or conditional modifications, such as the update() method and dictionary comprehensions.

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 is your go-to for merging one dictionary into another. It modifies the original dictionary in place by incorporating key-value pairs from a second dictionary or another iterable of key-value pairs.

  • If a key from the new data already exists, its value is overwritten—like how the 'email' was updated in the example.
  • If a key is new, it's simply added to the dictionary, which is what happened with the 'phone' key.

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 provide a powerful and readable way to create a new dictionary based on the items of an existing one. This one-liner iterates through the scores dictionary, applying a rule to each value.

  • It checks if a score is less than 90.
  • If true, it adds 5 to the score.
  • If false, it keeps the original score.

The resulting dictionary is then assigned back to the scores variable, effectively updating it. This approach is ideal for transformations that depend on a condition.

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}

When you're not sure if a key exists, the .get() method is a safe way to update a dictionary without causing a KeyError. This method tries to retrieve a key's value but provides a default if the key isn't found, which is perfect for tasks like counting items.

  • The expression inventory.get(fruit, 0) looks for the key. Since 'apples' exists, it returns its value, 10.
  • The code then adds 5 and updates the value to 15.
  • If the key didn't exist, .get() would return the default value 0, preventing an error and correctly initializing the count.

Advanced dictionary update techniques

As you move beyond common updates, Python offers more elegant solutions like dictionary unpacking with the ** operator, collections.defaultdict, and setdefault() for complex scenarios.

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}

The double-asterisk ** operator offers a clean way to merge dictionaries by unpacking their contents into a new one. Unlike the update() method, this approach is non-destructive and creates a new dictionary, leaving the original ones untouched. The order of unpacking is crucial.

  • When keys overlap, the value from the last dictionary unpacked takes precedence. Here, the timeout from user_config overwrites the one from defaults.
  • Unique keys from all dictionaries are combined into the final result.

This makes it an elegant solution for applying user-defined settings over a default configuration.

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 is a lifesaver for counting and grouping tasks. It behaves like a regular dictionary but automatically provides a default value for keys that don't exist yet. This prevents KeyError exceptions without you needing to perform manual checks.

  • In this example, defaultdict(int) sets the default value for any new key to 0—the result of calling int().
  • When the loop first sees a word, word_count[word] is initialized to 0 before += 1 runs.
  • This makes the code for counting items much cleaner than using .get().

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 setdefault() method offers a compact way to retrieve a key's value or, if the key is missing, insert it with a default value. This "get-or-set" operation modifies the dictionary in place, making it especially useful when the values are collections like lists.

  • When setdefault('Alice', []) runs, the key 'Alice' is new, so Python creates an empty list and adds it to the dictionary. The method then returns this new list, allowing .append() to add the phone number.
  • Since 'John' already exists, setdefault() just returns the existing list, and the new number is appended.

Move faster with Replit

Replit is an AI-powered development platform where all Python dependencies come pre-installed, so you can skip setup and start coding instantly. This lets you move from learning individual techniques to applying them right away.

To go from techniques to a complete application, there's Agent 4. Instead of piecing together methods like update() or setdefault(), you can describe the app you want to build, and Agent will handle the code, databases, and deployment. For example, you could build:

  • A configuration manager that applies user-defined settings over a default configuration, ensuring custom preferences are always prioritized.
  • A real-time analytics tool that counts occurrences of events, like button clicks or page views, without failing on the first instance of a new event.
  • A data aggregator that groups related information, like multiple phone numbers or email addresses, under a single contact name.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

Even with the right methods, you can run into a few common snags when updating dictionaries in Python.

Forgetting that dictionary keys must be hashable

One fundamental rule is that dictionary keys must be "hashable," meaning their value can't change. This is why you can use immutable types like strings, numbers, or tuples as keys, but not mutable types like lists or other dictionaries. If you try using a list as a key, Python will raise a TypeError because the list's contents could be modified, making it an unreliable identifier.

Avoiding KeyError when accessing nonexistent keys

A frequent stumble is the KeyError, which pops up when you try to access or modify a key that doesn't exist using square brackets. While this behavior is predictable, it can crash your program if not handled. You can sidestep this issue by using methods like .get() to safely retrieve a value or setdefault() to initialize it if it's missing.

Common pitfall with dictionary references

It's also easy to get tripped up by how Python handles dictionary assignments. When you write new_dict = old_dict, you aren't creating a copy. Instead, you're creating a second reference pointing to the exact same dictionary in memory.

  • Any change made through new_dict will also affect old_dict, which can lead to unexpected side effects.
  • To create a separate, independent copy, use the .copy() method or dictionary unpacking, like this: new_dict = old_dict.copy().

Forgetting that dictionary keys must be hashable

This rule about hashable keys is a common tripwire. Because lists are mutable, their contents can change, making them unsuitable as keys. Python enforces this by raising a TypeError, as you'll see in the following code when we try it.

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

The TypeError is triggered because the code attempts to use the list [1, 2] as a key, which is an invalid operation. The following example demonstrates the correct way to associate coordinates with a value in a dictionary.

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

To fix the TypeError, you simply swap the list for a tuple. The code works with (1, 2) because tuples are immutable—their values can't be changed, which makes them reliable as keys. Keep this in mind whenever you need to use a multi-part key, such as for geographic coordinates or composite identifiers. Using a tuple ensures your key remains constant and hashable, preventing unexpected errors in your program.

Avoiding KeyError when accessing nonexistent keys

A KeyError is a frequent stumbling block that halts your program unexpectedly. It occurs when you try to access a dictionary key that doesn't exist using square brackets. The following code demonstrates what happens when you request a non-existent 'age' key.

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

The script crashes because user_data['age'] is a direct demand for a key that isn't there. Since Python can't find it, the program stops with a KeyError. The following code shows how to handle this gracefully.

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 avoid the KeyError. Here’s how it works:

  • The expression user_data.get('age', 'unknown') safely looks for the 'age' key.
  • Since the key doesn't exist, it returns the default value, 'unknown', instead of crashing.

This is crucial when working with unpredictable data, like API responses or user input, where you can't guarantee every key will be present.

Common pitfall with dictionary references

This shared reference behavior can lead to subtle bugs that are hard to trace. Because both variables point to the same dictionary, a change made through one variable silently alters the other. See what happens when we modify the backup dictionary below.

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

Since backup is just another name for the original dictionary, modifying the nested theme value alters both. This silent change is a classic source of bugs. The following code shows how to create a true, independent copy.

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 completely independent copy using the copy.deepcopy() function. This method recursively duplicates the entire dictionary, including any nested objects inside it. This ensures that your backup is a true clone, not just another reference to the original.

  • Any changes made to the backup copy won't affect the original dictionary.
  • This is essential when you're modifying dictionaries that contain other mutable objects, like lists or other dictionaries.

Real-world applications

Moving beyond theory and errors, these update techniques are the building blocks for practical applications like configuration management and data analysis.

Managing app settings with the ** unpacking operator

The ** operator is especially useful for creating a final configuration in an application, where it layers user preferences on top of a default set of options.

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 double-asterisk ** operator creates a new dictionary by merging others. The order of unpacking is key—values from the rightmost dictionary take precedence when keys overlap.

  • Initially, the 'theme' from user_settings overwrites the default value.
  • After user_settings is modified, the merge is run again. This creates a completely new active_settings dictionary that includes the updated 'notifications' preference.

This non-destructive approach is great for dynamically combining configurations without altering the original sources.

Creating a word frequency analyzer with defaultdict

Building a word frequency analyzer is a classic example where defaultdict shines, as it lets you increment counters for new words without any setup.

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 code tallies word occurrences in a string. It uses defaultdict(int) to streamline the process, so you don't have to manually initialize counters for new words.

  • First, the code normalizes the text with .lower() and splits it into a list of words using .split().
  • The loop then increments the count for each word. If a word is new, defaultdict automatically creates an entry with a value of 0 before adding 1.

This avoids the need for extra checks inside the loop, making the code cleaner.

Get started with Replit

Put your knowledge into practice by building a tool. Just tell Replit Agent what you need: "Build a configuration manager for app settings" or "Create a real-time dashboard that counts event occurrences."

Replit Agent writes the code, tests for errors, and deploys the app for you. Start building with Replit.

Build your first app today

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.

Build your first app today

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.