How to Initialize a Dictionary in Python (With 0, Keys, Values and Defaults)

To initialize a dictionary in Python, write the keys and values in curly braces ({"a": 1}), start with an empty dictionary ({} or dict()), or build one from existing data with dict(zip(keys, values)) or a dictionary comprehension. To give every key the same starting value, such as 0, use dict.fromkeys(keys, 0):

scores = dict.fromkeys(["math", "science", "english"], 0)
print(scores)

Output:

{'math': 0, 'science': 0, 'english': 0}

Every example was run with Python 3.12.5; the output shown is from those runs.

8 ways to initialize a dictionary

a = {}                                        # empty dictionary
b = dict()                                    # also empty
c = {"apple": 3, "banana": 5}                 # literal with keys and values
d = dict(apple=3, banana=5)                   # keyword arguments (keys must be valid names)
e = dict([("apple", 3), ("banana", 5)])       # from a list of (key, value) pairs
f = dict(zip(["apple", "banana"], [3, 5]))    # from two lists
g = {fruit: 0 for fruit in ["apple", "banana"]}  # dictionary comprehension
h = dict.fromkeys(["apple", "banana"], 0)     # same value for every key

for name, value in zip("abcdefgh", [a, b, c, d, e, f, g, h]):
    print(name, value)

Output:

a {}
b {}
c {'apple': 3, 'banana': 5}
d {'apple': 3, 'banana': 5}
e {'apple': 3, 'banana': 5}
f {'apple': 3, 'banana': 5}
g {'apple': 0, 'banana': 0}
h {'apple': 0, 'banana': 0}
Command Prompt screenshot of 8 ways to initialize a Python dictionary and the printed result of each
All eight ways, run in the Command Prompt.
MethodUse it when
{} / dict()You’ll add keys later
{"k": v}You know the keys and values now
dict(k=v)Keys are simple names (no spaces, not numbers)
dict(pairs)You have a list of (key, value) tuples
dict(zip(keys, values))Keys and values are in two lists
{k: f(k) for k in ...}Values are computed, or each key needs its own list/dict
dict.fromkeys(keys, value)Every key gets the same immutable value (0, None, “”)

More on building from two lists: create a dictionary from two lists.

Initialize a dictionary with 0

Starting every key at 0 is the classic setup for counting:

words = "the cat and the hat and the bat".split()

counts = dict.fromkeys(set(words), 0)   # every word starts at 0
for w in words:
    counts[w] += 1
print(dict(sorted(counts.items())))

Output:

{'and': 2, 'bat': 1, 'cat': 1, 'hat': 1, 'the': 3}

Without the initialization, the first += 1 fails because the key doesn’t exist yet:

counts = {}
counts["the"] += 1

Output:

KeyError: 'the'

Let Python create the 0 for you

defaultdict(int) creates a missing key with int(), which is 0, the first time you use it. For counting, Counter does everything in one call (both are part of the collections module):

from collections import Counter, defaultdict

words = "the cat and the hat and the bat".split()

counts = defaultdict(int)          # missing keys start at int() == 0
for w in words:
    counts[w] += 1
print(dict(counts))

print(Counter(words))              # the same count in one line

Output:

{'the': 3, 'cat': 1, 'and': 2, 'hat': 1, 'bat': 1}
Counter({'the': 3, 'and': 2, 'cat': 1, 'hat': 1, 'bat': 1})
Command Prompt screenshot of counting words with collections.defaultdict(int) and Counter in Python
defaultdict(int) and Counter run in the Command Prompt.

Or use dict.get(key, 0) with a normal dictionary:

counts = {}
for w in "a b a c a".split():
    counts[w] = counts.get(w, 0) + 1    # 0 if the key isn't there yet
print(counts)

Output:

{'a': 3, 'b': 1, 'c': 1}

Initialize a dictionary with keys and values

keys = ["name", "age", "city"]
values = ["Ann", 34, "Boston"]

person = dict(zip(keys, values))
print(person)

person_default = dict.fromkeys(keys)     # value defaults to None
print(person_default)

Output:

{'name': 'Ann', 'age': 34, 'city': 'Boston'}
{'name': None, 'age': None, 'city': None}

dict.fromkeys(keys) without a value gives every key None, which is useful when you’ll fill in the values later.

The dict.fromkeys() trap: shared lists

fromkeys() puts the same object under every key. That’s fine for 0 or None, but not for a list or dict:

students = ["ann", "bob", "cy"]

grades = dict.fromkeys(students, [])     # ONE list shared by every key
grades["ann"].append(90)
print(grades)
print("same list?", grades["ann"] is grades["bob"])

Output:

{'ann': [90], 'bob': [90], 'cy': [90]}
same list? True
Command Prompt screenshot: dict.fromkeys with an empty list gives every key the same list, so appending 90 for one student changes all of them
The shared-list problem, reproduced in the Command Prompt.

Use a dictionary comprehension so each key gets its own list:

students = ["ann", "bob", "cy"]

grades = {s: [] for s in students}       # a new list for each key
grades["ann"].append(90)
print(grades)
print("same list?", grades["ann"] is grades["bob"])

Output:

{'ann': [90], 'bob': [], 'cy': []}
same list? False
Diagram: dict.fromkeys with a list makes every key point to one shared list, while a dictionary comprehension creates a separate list for each key
fromkeys(keys, []): one list for all keys. Comprehension: one list per key.

Initialize a dictionary of lists

from collections import defaultdict

orders = [("ann", "tea"), ("bob", "coffee"), ("ann", "cake")]

by_customer = defaultdict(list)          # missing keys start as []
for customer, item in orders:
    by_customer[customer].append(item)
print(dict(by_customer))

manual = {}
for customer, item in orders:
    manual.setdefault(customer, []).append(item)   # without defaultdict
print(manual)

Output:

{'ann': ['tea', 'cake'], 'bob': ['coffee']}
{'ann': ['tea', 'cake'], 'bob': ['coffee']}

More examples: Python dictionary of lists.

Initialize a nested dictionary

import json

stores = ["north", "south"]
months = ["jan", "feb"]

sales = {store: {month: 0 for month in months} for store in stores}
sales["north"]["jan"] = 120
print(json.dumps(sales, indent=2))

Output:

{
  "north": {
    "jan": 120,
    "feb": 0
  },
  "south": {
    "jan": 0,
    "feb": 0
  }
}

A dictionary with “dimensions” (grid)

For a 2-D table, use tuples as keys:

rows, cols = 2, 3
grid = {(r, c): 0 for r in range(rows) for c in range(cols)}   # a 2x3 "matrix"
grid[(1, 2)] = 5
print(grid)
print(len(grid), "cells")

Output:

{(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 0, (1, 1): 0, (1, 2): 5}
6 cells

Start from a template (copy vs deepcopy)

import copy

template = {"name": "", "tags": []}

shallow = dict(template)                 # copies the top level only
shallow["tags"].append("new")
print("template after shallow copy:", template)

template = {"name": "", "tags": []}
deep = copy.deepcopy(template)           # copies nested objects too
deep["tags"].append("new")
print("template after deepcopy:   ", template)

Output:

template after shallow copy: {'name': '', 'tags': ['new']}
template after deepcopy:    {'name': '', 'tags': []}

dict(template) and template.copy() only copy the outer dictionary, so nested lists are still shared. Use copy.deepcopy() for templates that contain lists or dicts.

Initialize an empty dictionary

{} and dict() both create an empty dictionary. {} is not an empty set; use set() for that:

print(type({}), type(set()), type({1, 2}))

Output:

<class 'dict'> <class 'set'> <class 'set'>

With a type hint (Python 3.9+):

inventory: dict[str, int] = {}
inventory["apples"] = 12
print(inventory, inventory.__class__.__name__)

Output:

{'apples': 12} dict

Details: create an empty dictionary in Python and check if a dictionary is empty.

Speed of each method

import timeit

for stmt in ["{}", "dict()", "{'a': 0, 'b': 0, 'c': 0}", "dict.fromkeys('abc', 0)", "{k: 0 for k in 'abc'}"]:
    t = min(timeit.repeat(stmt, number=1_000_000, repeat=5))
    print(f"{stmt:26} {t * 1000:6.0f} ns")

Output:

{}                             15 ns
dict()                         31 ns
{'a': 0, 'b': 0, 'c': 0}       52 ns
dict.fromkeys('abc', 0)       135 ns
{k: 0 for k in 'abc'}         104 ns

Times are nanoseconds per operation, from one run on a laptop. {} is faster than dict() because it is a literal rather than a function call, but all of these are fast enough for normal code.

Common mistake: a dictionary as a default argument

def add_score(name, scores={}):          # the {} is created only once!
    scores[name] = scores.get(name, 0) + 1
    return scores

print(add_score("ann"))
print(add_score("bob"))                  # still contains ann

def add_score_fixed(name, scores=None):
    if scores is None:
        scores = {}                      # a new dict on every call
    scores[name] = scores.get(name, 0) + 1
    return scores

print(add_score_fixed("ann"))
print(add_score_fixed("bob"))

Output:

{'ann': 1}
{'ann': 1, 'bob': 1}
{'ann': 1}
{'bob': 1}

Default values are created once, when the function is defined, so every call shares that one dictionary. Use None as the default and create the dictionary inside the function.

Continue with these dictionary tutorials:

Frequently asked questions

How do I initialize a dictionary with 0 in Python?

dict.fromkeys(keys, 0) or {k: 0 for k in keys}. For counting, collections.defaultdict(int) or Counter create the 0 automatically.

How do I initialize a dictionary with keys and values?

Write them directly ({"a": 1, "b": 2}), or combine two lists with dict(zip(keys, values)).

How do I initialize an empty dictionary?

d = {} or d = dict(). {} is a dictionary, not a set.

Why do all my keys change when I append to one list?

dict.fromkeys(keys, []) stores the same list under every key. Use {k: [] for k in keys} or defaultdict(list).

How do I initialize a dictionary with a default value for missing keys?

Use collections.defaultdict, for example defaultdict(int) (0), defaultdict(list) ([]) or defaultdict(lambda: "n/a"), or read with d.get(key, default).

Is a Python dictionary a hash map?

Yes. dict is Python’s built-in hash map: keys are hashed for fast lookups, and since Python 3.7 it also keeps insertion order.