How to initialize a dictionary in Python

Learn how to initialize a Python dictionary. Explore various methods, tips, real-world applications, and common error debugging.

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

Python dictionaries are essential to store data in key-value pairs. You can initialize a dictionary with curly braces {} or the dict() constructor, which provides a flexible foundation for data manipulation.

In this article, you’ll explore several initialization techniques. You'll also find practical tips, see real-world applications, and get advice on how to debug common issues to master this fundamental skill.

Creating a dictionary with curly braces {}

student = {"name": "John", "age": 21, "courses": ["Math", "Science"]}
print(student)--OUTPUT--{'name': 'John', 'age': 21, 'courses': ['Math', 'Science']}

Using curly braces {} is the most direct way to define a dictionary. This approach, known as a dictionary literal, is perfect when you already know the data you want to store. The example demonstrates a few key points:

  • Readability: The key-value structure is clear and easy to understand at a glance.
  • Mixed Data Types: You can store different types of data, like the string "John", the integer 21, and the list of courses, all in one dictionary.
  • Flexibility: This allows you to create complex data structures that can represent real-world information effectively.

Basic dictionary initialization methods

While curly braces are perfect for predefined data, Python also offers several other powerful techniques for creating dictionaries when your data isn't known in advance.

Using the dict() constructor

student = dict(name="John", age=21, courses=["Math", "Science"])
print(student)--OUTPUT--{'name': 'John', 'age': 21, 'courses': ['Math', 'Science']}

The dict() constructor offers a clean alternative for initialization. Instead of string literals, you pass keys as keyword arguments—like name="John". This can make your code feel more like setting attributes on an object.

  • Cleaner Syntax: Keys don't require quotes, which can make the code look less cluttered.
  • Key Limitations: This method only works if your keys are valid Python identifiers. You can't use integers or strings with spaces like "first name".

Using dict.fromkeys() method

keys = ["name", "age", "grade"]
student = dict.fromkeys(keys, "Unknown")
print(student)--OUTPUT--{'name': 'Unknown', 'age': 'Unknown', 'grade': 'Unknown'}

The dict.fromkeys() method is perfect when you need to create a dictionary where all keys share the same initial value. It takes an iterable, like the keys list, and a single value—in this case, "Unknown"—to assign to each new key. This approach is a quick way to set up a dictionary's structure before you have the final data.

  • It’s especially useful for creating a template or placeholder dictionary that you can populate later.
  • If you don't provide a second argument for the value, each key will default to None.

Using dictionary comprehension

names = ["John", "Emma", "Alex"]
scores = [85, 92, 78]
student_scores = {name: score for name, score in zip(names, scores)}
print(student_scores)--OUTPUT--{'John': 85, 'Emma': 92, 'Alex': 78}

Dictionary comprehension offers a concise and elegant way to create dictionaries from iterables. The zip() function first pairs each name with its corresponding score. The comprehension then iterates through these pairs, assigning each name as a key and each score as its value.

  • It’s a powerful, Pythonic way to build dictionaries dynamically.
  • This method combines the loop and dictionary creation into a single, expressive line, making your code more compact.

Advanced dictionary initialization techniques

Building on those foundational methods, you can unlock even more flexibility by merging dictionaries, nesting them, using specialized tools like defaultdict, or creating lists of dictionaries for cleaner code.

Merging dictionaries with the | operator

personal_info = {"name": "John", "age": 21}
academic_info = {"major": "Computer Science", "GPA": 3.8}
student = personal_info | academic_info # Python 3.9+ syntax
print(student)--OUTPUT--{'name': 'John', 'age': 21, 'major': 'Computer Science', 'GPA': 3.8}

Introduced in Python 3.9, the pipe operator | offers a sleek way to merge two dictionaries. It combines the key-value pairs from both personal_info and academic_info into a single new dictionary. This modern syntax is often more readable than older methods for merging two dictionaries.

  • Key Overwrites: If both dictionaries share a key, the value from the second (right-hand) dictionary will be used in the final result.
  • Immutability: The original dictionaries, personal_info and academic_info, remain unchanged by the operation.

Creating nested dictionaries

students = {
"John": {"age": 21, "courses": ["Math", "Science"]},
"Emma": {"age": 20, "courses": ["History", "English"]}
}
print(students["John"]["courses"])--OUTPUT--['Math', 'Science']

Nested dictionaries let you store a dictionary as a value inside another one, creating a hierarchical structure. This is perfect for organizing complex, related data. In the example, the main students dictionary maps each name to another dictionary containing that student's specific details.

  • To access nested data, you simply chain the keys. The expression students["John"]["courses"] first retrieves the value for the key "John" and then gets the value for "courses" from that inner dictionary.
  • This layering is essential for managing structured data, such as information retrieved from APIs or JSON files.

Using defaultdict for automatic initialization

from collections import defaultdict
student_grades = defaultdict(list)
student_grades["John"].append(85)
student_grades["John"].append(92)
print(dict(student_grades))--OUTPUT--{'John': [85, 92]}

The defaultdict from the collections module is a lifesaver when you're dealing with keys that might not exist yet. It automatically provides a default value for a missing key, so you don't have to write extra code to check for it first.

  • It prevents the dreaded KeyError that normally occurs when you try to access or modify a key that isn't in the dictionary.
  • In this example, defaultdict(list) ensures that if a student's name isn't already a key, an empty list is created for it on the fly. This lets you immediately append() grades without any setup.

Move faster with Replit

Replit is an AI-powered development platform where you can start coding Python instantly. It comes with all dependencies pre-installed, so you can skip the tedious setup and environment configuration.

While mastering methods like dict.fromkeys() or the merge operator | is crucial, the real goal is to build working applications. This is where Agent 4 comes in. It helps you move from piecing together individual techniques to creating complete products directly from a description.

  • A data importer that takes separate lists of names and emails and combines them into a structured contact dictionary.
  • A settings manager that creates a default configuration for an application, which can later be populated with user-specific values.
  • A gradebook tool that groups multiple test scores under each student's name, perfect for using a defaultdict.

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 initialization method, you can run into a few common pitfalls when working with dictionaries.

Avoiding KeyError when accessing non-existent dictionary keys

One of the most frequent issues is the KeyError, which appears when you try to access a key that doesn't exist. While defaultdict is a great solution, you can also handle this gracefully using other built-in tools.

  • The get() method is a safer way to retrieve values. Instead of causing an error, it returns None for a missing key, or you can provide a specific default like my_dict.get('key', 'default').
  • You can also check if a key exists before accessing it using the in keyword, as in the expression if 'my_key' in my_dict:.

Avoiding errors when modifying a dictionary during iteration

Python will raise a RuntimeError if you try to change a dictionary's size—by adding or removing keys—while iterating over it. To avoid this, loop over a static copy of the keys by creating one with list(my_dict.keys()). This lets you safely modify the original dictionary within the loop.

Using immutable types as dictionary keys

A fundamental rule is that dictionary keys must be immutable, meaning their value cannot change after creation. This is why you can use types like strings, numbers, and tuples as keys, but not mutable types like lists or other dictionaries.

If you attempt to use a mutable key, you'll get a TypeError. This restriction is essential because Python relies on a key's consistent hash value to locate its data efficiently; if the key could change, its hash would too, breaking the lookup mechanism.

Avoiding KeyError when accessing non-existent dictionary keys

A KeyError is what you'll get if you try to retrieve a value using a key that isn't in the dictionary. It's a common roadblock that immediately stops your script. See this error in action in the following example.

student_scores = {"John": 85, "Emma": 92}
print(student_scores["Alex"]) # This will raise KeyError: 'Alex'

The code attempts to access student_scores["Alex"], but "Alex" isn't a key in the dictionary, which triggers the KeyError. To prevent your program from crashing, you need a way to handle these situations. The following code demonstrates one approach.

student_scores = {"John": 85, "Emma": 92}
print(student_scores.get("Alex", "Not found"))

Here, the get() method prevents a crash by providing a fallback. Since the key "Alex" is missing, student_scores.get("Alex", "Not found") returns the default string "Not found" instead of raising an error. You'll find this technique essential when handling data from external sources, like APIs or user forms, where the presence of certain keys isn't guaranteed. For more comprehensive strategies on solving KeyError issues, consider additional error-handling approaches. If no default is set, it returns None.

Avoiding errors when modifying a dictionary during iteration

Avoiding errors when modifying a dictionary during iteration

Modifying a dictionary while you're looping over it is a classic trap. Python protects its internal structure by raising a RuntimeError if you add or remove keys during iteration, as this can lead to unpredictable behavior. The following code demonstrates this common mistake.

scores = {"John": 65, "Emma": 45, "Alex": 90}
for name, score in scores.items():
if score < 50:
del scores[name] # RuntimeError: dictionary changed size during iteration
print(scores)

The RuntimeError happens because del scores[name] tries to alter the dictionary's size while the loop is still iterating over it with scores.items(). This creates an unstable state. The following code shows a safe way around this issue.

scores = {"John": 65, "Emma": 45, "Alex": 90}
passing_scores = {name: score for name, score in scores.items() if score >= 50}
print(passing_scores)

The solution avoids a RuntimeError by building a new dictionary instead of modifying the original during iteration. A dictionary comprehension cleanly filters the scores dictionary, creating passing_scores with only the desired items. This is the go-to method whenever you need to remove elements from a dictionary based on a condition.

  • It’s safe because the original dictionary remains untouched during the operation.
  • It’s also highly readable and considered Pythonic.

Using immutable types as dictionary keys

Using immutable types as dictionary keys

You'll encounter a TypeError if you try using a mutable object, like a list, as a dictionary key. Python's lookup system requires keys to be "hashable," meaning they have a fixed value that can't change after they're created.

Because a list's contents can be modified, its hash value is unstable, which breaks the dictionary's internal logic. The following example demonstrates what happens when you try to use a list as a key, triggering an "unhashable type" error.

student_grades = {}
courses = ["Math", "Science"]
student_grades[courses] = [85, 92] # TypeError: unhashable type: 'list'
print(student_grades)

The code attempts to use the courses list directly as a dictionary key. This action is invalid because a key's value must be fixed. The following example demonstrates the correct approach for this scenario.

student_grades = {}
courses = ("Math", "Science") # Using immutable tuple instead of list
student_grades[courses] = [85, 92]
print(student_grades)

The solution is to swap the mutable list for an immutable tuple. By changing the courses variable to ("Math", "Science"), you create a hashable key that Python can work with, which resolves the TypeError. You'll often need this fix when using composite data—like a pair of strings or coordinates—as a unique identifier in a dictionary.

Real-world applications

With those common errors handled, you can now apply these dictionary skills with vibe coding to build powerful tools for real-world data processing tasks.

Creating a frequency counter with dict.get()

One of the most practical uses for the get() method is building a frequency counter, which tallies how many times each item appears in a dataset.

text = "apple banana apple orange banana apple"
word_count = {}
for word in text.split():
word_count[word] = word_count.get(word, 0) + 1
print(word_count)

This snippet demonstrates a clever way to count items in a sequence. The code iterates over each word from text.split() and uses a single line to update the word_count dictionary.

  • The get(word, 0) method is the workhorse here. It safely fetches the current count for a word.
  • If a word isn't in the dictionary yet, get() returns the default value 0, which prevents a KeyError.
  • Finally, + 1 increments the count, and the result is assigned back to the word's key.

Implementing a simple memoization cache with dictionaries

Dictionaries are also excellent for memoization, a powerful optimization technique that caches the results of expensive function calls to avoid redundant calculations.

cache = {}

def calculate_expensive_value(x):
if x in cache:
return f"From cache: {cache[x]}"
result = x * x * x # Simulate expensive calculation
cache[x] = result
return f"Calculated: {result}"

print(calculate_expensive_value(5))
print(calculate_expensive_value(5)) # Second call uses cache

The calculate_expensive_value() function uses a cache dictionary to store its results. When you call the function, it first checks if the answer for a given input x already exists in the cache. This simple check avoids re-running a costly calculation if the work has already been done.

  • If the result is found, the function returns the stored value directly, which is much faster.
  • If it's not found, the function performs the calculation, saves the result to the cache for next time, and then returns it.

Get started with Replit

Now, use your knowledge to build a real tool. Tell Replit Agent to "build a word frequency counter from a text file" or "create a gradebook that groups student scores."

Replit Agent writes the code, tests for errors, and deploys the app, turning your description into a finished product. 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.