Create an Empty Dictionary in Python ({} vs dict())

Creating an empty dictionary in Python takes one pair of braces:

scores = {}          # the usual way
totals = dict()      # identical result

Both give you a real dictionary with no keys in it. The braces are the common choice, and they are marginally faster, but the two are interchangeable.

What follows covers filling it afterwards, starting one with keys already in place, and the three ways an empty dictionary can misbehave. Output is from a run on Python 3.12.5.

Diagram comparing curly braces dict fromkeys and a dictionary comprehension for creating an empty Python dictionary
Five ways to start a dictionary, and what each one actually produces.

Declare an empty dictionary with {} or dict()

The two spellings produce exactly the same object:

# the literal - this is the one to use
scores = {}

# the constructor - identical result
totals = dict()

print("scores   ->", scores, type(scores))
print("totals   ->", totals, type(totals))
print("equal?   ->", scores == totals)
print("length   ->", len(scores))
print()
print("both are empty dictionaries; there is no third kind.")

Output:

scores   -> {} <class 'dict'>
totals   -> {} <class 'dict'>
equal?   -> True
length   -> 0

both are empty dictionaries; there is no third kind.
Command Prompt showing an empty Python dictionary created with curly braces and with the dict constructor
{} and dict() both build an empty dictionary.

There is no separate step to declare or initialise a dictionary in Python. Assigning {} to a name is the whole thing, and the dictionary grows as you add keys.

Is {} faster than dict() for an empty dictionary?

Slightly, and for a reason worth knowing:

import timeit

print("building 5,000,000 empty dictionaries:")
print(f"  {{}}        {timeit.timeit('{}', number=5000000):.3f}s")
print(f"  dict()     {timeit.timeit('dict()', number=5000000):.3f}s")
print()
print("the literal is quicker because it is a single bytecode instruction,")
print("while dict() is a name lookup followed by a function call.")
print()
print("dict() still earns its place when you are building from something:")
print("  dict(a=1, b=2)              ->", dict(a=1, b=2))
print("  dict([('a', 1), ('b', 2)])  ->", dict([("a", 1), ("b", 2)]))

Output:

building 5,000,000 empty dictionaries:
  {}        0.086s
  dict()     0.161s

the literal is quicker because it is a single bytecode instruction,
while dict() is a name lookup followed by a function call.

dict() still earns its place when you are building from something:
  dict(a=1, b=2)              -> {'a': 1, 'b': 2}
  dict([('a', 1), ('b', 2)])  -> {'a': 1, 'b': 2}

{} compiles to a single instruction. dict() has to look the name up and call it, which is why it trails on a tight loop.

The gap is far too small to matter in ordinary code. Use dict() freely when you are building from keyword arguments or a list of pairs, since that is what it is good at.

Why {} is not an empty set

This trips people up because the braces are shared between two types:

maybe_a_set = {}

print("empty curly braces give you a DICTIONARY:")
print("  {}        ->", maybe_a_set, type(maybe_a_set))
print()
print("an empty set needs the constructor:")
print("  set()     ->", set(), type(set()))
print()
print("  {} == set() ->", {} == set())
print()
print("once there is something inside, the braces are unambiguous:")
print("  {1, 2}          ->", {1, 2}, type({1, 2}))
print("  {'a': 1}        ->", {"a": 1}, type({"a": 1}))

Output:

empty curly braces give you a DICTIONARY:
  {}        -> {} <class 'dict'>

an empty set needs the constructor:
  set()     -> set() <class 'set'>

  {} == set() -> False

once there is something inside, the braces are unambiguous:
  {1, 2}          -> {1, 2} <class 'set'>
  {'a': 1}        -> {'a': 1} <class 'dict'>
Command Prompt showing that empty curly braces create a dictionary in Python and that an empty set needs the set constructor
Empty braces give a dictionary; an empty set needs set().

Dictionaries got the braces first, so {} means an empty dictionary and set() is the only way to write an empty set. Once there is content inside, the comma or colon tells Python which you meant.

How to add to an empty dictionary

The obvious next question, and there are three useful ways:

inventory = {}

# one key at a time
inventory["apples"] = 10
inventory["pears"] = 4

# several at once
inventory.update({"plums": 7, "figs": 2})

# only if the key is not already there
inventory.setdefault("apples", 999)
inventory.setdefault("dates", 5)

print("inventory ->", inventory)
print()
print("setdefault left apples at 10 because the key already existed,")
print("and it added dates because that one did not.")
print()

print("building one inside a loop:")
counts = {}
for fruit in ["apple", "pear", "apple"]:
    counts[fruit] = counts.get(fruit, 0) + 1
print("counts    ->", counts)

Output:

inventory -> {'apples': 10, 'pears': 4, 'plums': 7, 'figs': 2, 'dates': 5}

setdefault left apples at 10 because the key already existed,
and it added dates because that one did not.

building one inside a loop:
counts    -> {'apple': 2, 'pear': 1}

Square bracket assignment adds or overwrites. update() merges several at once. setdefault() only writes when the key is absent, which makes it handy for building up counts and groups.

The get(key, 0) pattern in that loop avoids a KeyError on the first sighting of a word. There is more in adding items to a dictionary.

Create a dictionary with keys but no values

Sometimes what you want is the keys laid out in advance:

keys = ["name", "email", "phone"]

blank = dict.fromkeys(keys)
print("dict.fromkeys(keys)        ->", blank)
print("every value is None until you fill it in")
print()

zeros = dict.fromkeys(keys, 0)
print("dict.fromkeys(keys, 0)     ->", zeros)
print()

print("a comprehension does the same and is easier to adapt:")
print("{k: 0 for k in keys}       ->", {k: 0 for k in keys})

Output:

dict.fromkeys(keys)        -> {'name': None, 'email': None, 'phone': None}
every value is None until you fill it in

dict.fromkeys(keys, 0)     -> {'name': 0, 'email': 0, 'phone': 0}

a comprehension does the same and is easier to adapt:
{k: 0 for k in keys}       -> {'name': 0, 'email': 0, 'phone': 0}

dict.fromkeys() sets every value to None unless you pass a default. Strictly this is not an empty dictionary any more, because it has keys, so a test like if not d: will report it as non-empty.

To find out whether a dictionary really has nothing in it, see checking if a dictionary is empty.

Why dict.fromkeys shares one list between keys

Passing a mutable default to fromkeys() does something people rarely expect:

keys = ["a", "b"]

shared = dict.fromkeys(keys, [])
shared["a"].append(1)

print("dict.fromkeys(keys, []) then shared['a'].append(1):")
print("  shared            ->", shared)
print("  b changed too, because both keys point at ONE list")
print("  shared['a'] is shared['b'] ->", shared["a"] is shared["b"])
print()

separate = {k: [] for k in keys}
separate["a"].append(1)

print("a comprehension builds a NEW list per key:")
print("  separate          ->", separate)
print("  separate['a'] is separate['b'] ->", separate["a"] is separate["b"])
print()
print("the same applies to {} , set() or any other mutable default.")

Output:

dict.fromkeys(keys, []) then shared['a'].append(1):
  shared            -> {'a': [1], 'b': [1]}
  b changed too, because both keys point at ONE list
  shared['a'] is shared['b'] -> True

a comprehension builds a NEW list per key:
  separate          -> {'a': [1], 'b': []}
  separate['a'] is separate['b'] -> False

the same applies to {} , set() or any other mutable default.
Command Prompt showing dict.fromkeys giving every key the same list object so appending to one changes them all
fromkeys evaluates the default once, so every key shares one list.

The default is evaluated a single time and then handed to every key. Appending to one therefore appears to change all of them, because there was only ever one list.

A dictionary comprehension runs the expression again for each key, so every key gets its own list.

Use fromkeys for immutable defaults such as 0 or None, and a comprehension for anything you plan to modify. Initialising a dictionary with keys and values has more of these patterns.

clear() versus assigning a new empty dict

These look equivalent and are not:

settings = {"theme": "dark"}
backup = settings            # both names, one dictionary

settings.clear()
print("after settings.clear():")
print("  settings ->", settings)
print("  backup   ->", backup, "  the same object was emptied")
print()

settings = {"theme": "dark"}
backup = settings

settings = {}
print("after settings = {}:")
print("  settings ->", settings)
print("  backup   ->", backup, "  a NEW dict was made; backup kept the old one")
print()
print("clear() empties what everyone is looking at.")
print("Rebinding only changes where this one name points.")

Output:

after settings.clear():
  settings -> {}
  backup   -> {}   the same object was emptied

after settings = {}:
  settings -> {}
  backup   -> {'theme': 'dark'}   a NEW dict was made; backup kept the old one

clear() empties what everyone is looking at.
Rebinding only changes where this one name points.