How to add a key value pair to a dictionary in Python

Learn to add key-value pairs to a Python dictionary with multiple methods. Explore tips, real-world applications, and how to fix common errors.

How to add a key value pair to a dictionary in Python
Published on: 
Thu
Feb 12, 2026
Updated on: 
Mon
Apr 13, 2026
The Replit Team

Python dictionaries store data as key-value pairs, a fundamental structure for many applications. To add a new pair, you can use simple syntax like the subscript operator [].

In this article, you'll explore several techniques to add new pairs. You will find practical tips, see real-world applications, and get debugging advice to handle dictionary data effectively.

Using square bracket notation to add a key-value pair

user_info = {"name": "John", "age": 30}
user_info["email"] = "john@example.com"
print(user_info)--OUTPUT--{'name': 'John', 'age': 30, 'email': 'john@example.com'}

The square bracket notation [] provides the most direct way to add a new entry. When you use an assignment like user_info["email"] = "john@example.com", Python first checks if the key "email" exists. Since it doesn't, Python creates the new key and assigns it the specified value.

This method is powerful because the same syntax handles two different scenarios. It's context-aware:

  • If the key is new, it adds the key-value pair to the dictionary.
  • If the key already exists, it simply updates the value associated with that key.

Basic dictionary modification methods

Beyond the directness of square brackets, you can use methods like update(), dict.fromkeys(), and dictionary comprehensions to add multiple items or initialize dictionaries efficiently.

Using the update() method to add key-value pairs

student = {"id": 101, "name": "Alice"}
student.update({"grade": "A", "course": "Python"})
print(student)--OUTPUT--{'id': 101, 'name': 'Alice', 'grade': 'A', 'course': 'Python'}

The update() method is your go-to for merging one dictionary into another. It takes a dictionary as its argument and efficiently adds all of its key-value pairs to the original, making it a versatile tool for updating dictionary values.

  • It adds any new keys, like grade and course, to the student dictionary.
  • If a key already exists, its value is simply updated—making it a versatile tool for both adding and modifying data.

Creating dictionaries with initial values using dict.fromkeys()

keys = ["apple", "banana", "cherry"]
fruit_dict = dict.fromkeys(keys, 0)
fruit_dict["mango"] = 5
print(fruit_dict)--OUTPUT--{'apple': 0, 'banana': 0, 'cherry': 0, 'mango': 5}

The dict.fromkeys() method is perfect for creating a dictionary when you have a list of keys and want to assign them all the same initial value. It takes an iterable, like the keys list, and a default value, in this case 0, to quickly build the dictionary. This technique complements other methods for creating dictionaries in Python.

  • This is especially useful for initializing data structures, like a fruit inventory where every item starts at zero.

Once the dictionary is created, it’s fully editable. You can still add new key-value pairs, such as setting mango to 5, using other methods.

Using dictionary comprehension to create and add items

original = {"a": 1, "b": 2}
new_items = {"c": 3, "d": 4}
combined = {**original, **new_items}
# Alternative using comprehension
combined_alt = {k: v for d in (original, new_items) for k, v in d.items()}
print(combined)--OUTPUT--{'a': 1, 'b': 2, 'c': 3, 'd': 4}

The dictionary unpacking operator ** offers a clean, modern syntax for merging dictionaries. It lets you expand the key-value pairs from original and new_items into a new dictionary, combined, all in one go.

  • The ** operator unpacks each dictionary’s contents into a new dictionary literal, creating a single, merged result.
  • A dictionary comprehension provides an alternative, building the new dictionary by explicitly looping through each source dictionary and its items.

Advanced dictionary techniques

For more complex scenarios, Python provides tools like setdefault() and defaultdict that automatically handle missing keys, saving you from writing extra conditional logic.

Using setdefault() to add keys conditionally

config = {"theme": "dark", "font_size": 12}
config.setdefault("language", "en") # Adds only if key doesn't exist
config.setdefault("theme", "light") # Does nothing as key exists
print(config)--OUTPUT--{'theme': 'dark', 'font_size': 12, 'language': 'en'}

The setdefault() method offers a safe way to add keys without overwriting existing data. It checks for a key's presence before acting, which is great for setting up defaults.

  • When you call config.setdefault("language", "en"), it adds the key because "language" is missing from the dictionary.
  • The call config.setdefault("theme", "light") has no effect, since the "theme" key already exists.

This makes it perfect for initializing values without the risk of accidentally changing data that's already there.

Working with defaultdict for automatic key creation

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

The defaultdict from the collections module is a lifesaver when you're counting or grouping items. It works by calling a "default factory" function—in this case, int—to create a value for any key that doesn't exist yet. This means you don't have to manually check if a key is present before using it.

  • When the code tries to access a new word for the first time, defaultdict automatically initializes its count to 0 (the result of int()), so the += 1 operation works without errors.

Handling nested dictionaries with dynamic path creation

def add_nested(d, path, value):
keys = path.split('.')
for key in keys[:-1]:
d = d.setdefault(key, {})
d[keys[-1]] = value

user_data = {}
add_nested(user_data, "profile.contact.email", "user@example.com")
print(user_data)--OUTPUT--{'profile': {'contact': {'email': 'user@example.com'}}}

When you're dealing with deeply nested data, creating the structure on the fly can be a hassle with traditional methods, but AI-powered coding makes it simpler. This custom add_nested function elegantly solves the problem by taking a string path and automatically building the dictionary structure for you.

  • It splits the path, like "profile.contact.email", and iterates through each part.
  • For each key in the path, it uses setdefault(key, {}) to ensure a nested dictionary exists before moving to the next level.
  • Finally, it assigns the value to the last key, completing the structure without needing manual checks.

Move faster with Replit

Replit is an AI-powered development platform where you can skip setup and start coding instantly, since all Python dependencies pre-installed. This lets you move from learning individual techniques to building complete applications with Agent 4.

Instead of piecing together methods like update() or setdefault(), you can describe the app you want to build and let the Agent handle the code, databases, and deployment. For example, you could build:

  • A word frequency counter that uses defaultdict to analyze text and return a dictionary of counts.
  • A configuration manager that builds a nested dictionary from user settings, applying default values with setdefault().
  • A data importer that merges new information into an existing user profile dictionary.

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

Common errors and challenges

While adding data is usually straightforward, you can run into common pitfalls like a KeyError, issues with mutable defaults, or accidental overwrites. Understanding these challenges is key to writing more robust and predictable code. You’ll learn how to handle non-existent keys gracefully, avoid the classic mutable default argument trap with {}, and prevent unintended data loss when using the [] operator.

Avoiding KeyError when accessing non-existent keys

A KeyError is one of the most common exceptions you'll encounter. It occurs when you try to access a key with the [] operator that isn't in the dictionary, which can crash your program. This often happens with unpredictable data. The following code demonstrates this exact issue.

user_settings = {"theme": "dark", "notifications": True}
font_size = user_settings["font_size"] # This will raise KeyError
print(f"Font size: {font_size}")

Since the "font_size" key is missing from the user_settings dictionary, the program fails when it tries to access it. You can prevent this crash by checking for the key first, as shown in the example below.

user_settings = {"theme": "dark", "notifications": True}
font_size = user_settings.get("font_size", 12) # Uses default value if key doesn't exist
print(f"Font size: {font_size}")

The get() method provides a safe way to retrieve values. It looks for a key, like "font_size", and if it can't find it, returns a default value—in this case, 12—instead of raising a KeyError. This approach is perfect when you're handling unpredictable data, such as user input or API responses, as it prevents your program from crashing over a missing key. You get the value you need or a sensible default, following best practices for accessing dictionary values.

Avoiding issues with mutable {} default parameters

It’s a common mistake to use a mutable object like an empty dictionary {} as a default function argument. Python creates this default dictionary only once, so every call to the function modifies the same object, causing unexpected behavior. See what happens in the following code.

def add_score(scores_dict={}):
scores_dict["player1"] = scores_dict.get("player1", 0) + 100
return scores_dict

result1 = add_score()
print(result1)
result2 = add_score()
print(result2) # Shows {'player1': 200} instead of {'player1': 100}

The second call to add_score() reuses the same dictionary from the first call instead of creating a new one, causing the score to accumulate unexpectedly. The corrected code below demonstrates how to ensure each call is independent.

def add_score(scores_dict=None):
if scores_dict is None:
scores_dict = {}
scores_dict["player1"] = scores_dict.get("player1", 0) + 100
return scores_dict

result1 = add_score()
print(result1)
result2 = add_score()
print(result2) # Correctly shows {'player1': 100}

The corrected add_score function avoids this trap by setting the default parameter to None. Inside, it checks if scores_dict is None and, if so, creates a new empty dictionary {}. This ensures each call operates on a fresh dictionary, preventing the shared state that caused the bug. You should watch for this whenever using mutable types like lists or dictionaries as default arguments in your functions, and consider copying dictionaries when needed.

Preventing accidental key overwriting with [] notation

The square bracket [] notation is convenient for both adding and updating dictionary entries. However, this dual functionality is a double-edged sword. It's easy to accidentally overwrite an existing value when you only meant to add a new one. The following code shows exactly how this can happen.

customer = {"id": 123, "name": "John"}
customer["id"] = "A123" # Overwrites the integer ID with a string
print(customer)

The assignment customer["id"] = "A123" overwrites the original integer ID with a string because the [] operator doesn't check if the key already exists. This can lead to silent data loss. The example below shows how to guard against this.

customer = {"id": 123, "name": "John"}
if "id" not in customer:
customer["id"] = "A123"
else:
customer["customer_id"] = "A123" # Use a different key
print(customer)

To prevent accidental overwrites, you can check if a key exists before assigning a value. The if "id" not in customer: statement ensures you only add the key if it's missing. If the key is already present, you can choose a different action, like creating a new key such as customer_id. This approach is crucial when merging data or handling user input, where you can't be sure which keys are already in use.

Real-world applications

Beyond avoiding errors, these dictionary techniques are fundamental to building practical applications like contact managers and text analyzers.

Building a contact manager with update() and bracket notation

You can build a simple contact manager by using bracket notation [] for adding individual contacts and the update() method for adding several at a time.

contacts = {}
# Add new contact using bracket notation
contacts["John"] = {"phone": "555-1234", "email": "john@example.com"}
# Add multiple contacts using update()
contacts.update({
"Sarah": {"phone": "555-5678", "email": "sarah@example.com"},
"Mike": {"phone": "555-9012", "email": "mike@example.com"}
})
print(contacts["Sarah"])

This code snippet initializes an empty dictionary called contacts and populates it using two different techniques. This approach creates a nested structure where each key—a name—maps to another dictionary holding that person's details.

  • First, it adds a single entry for "John" using the direct assignment of the square bracket [] operator.
  • Then, it uses the update() method to efficiently merge multiple new entries for "Sarah" and "Mike" from another dictionary.

Creating a frequency counter for text analysis with setdefault()

The setdefault() method is perfect for building a word frequency counter because it neatly handles the logic of initializing a word’s count the first time you encounter it.

text = "to be or not to be that is the question"
word_freq = {}
for word in text.split():
word_freq.setdefault(word, 0)
word_freq[word] += 1

print(word_freq)

This snippet efficiently counts word occurrences in a string through vibe coding. It iterates through each word and uses a two-part strategy to update the word_freq dictionary.

  • First, word_freq.setdefault(word, 0) prepares the dictionary. It checks for the word; if it's missing, it adds it with a count of 0. If the word already exists, this step does nothing.
  • Immediately after, word_freq[word] += 1 increments the count. This combination ensures you can safely update the count without needing a separate if/else block to handle new words.

Get started with Replit

Turn your knowledge into a real tool with Replit Agent. Describe what you want to build, like “a currency converter that stores rates in a dictionary” or “a tool that counts word frequencies from a text file.”

Replit Agent writes the code, tests for errors, and deploys your application. You just provide the instructions. 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.