Append to a Dictionary in Python (There Is No append Method)

Python dictionaries have no .append() method. You add to one by assigning to a key:

scores = {"ann": 90}
scores["bob"] = 85        # {"ann": 90, "bob": 85}

Calling .append() on a dictionary raises AttributeError, because that method belongs to lists. A list adds to the end; a dictionary needs you to say which key.

What follows covers adding one key, adding several, merging two dictionaries, and the case most people actually mean: appending to a list stored as a value. Output is from Python 3.12.5.

Diagram comparing dictionary append attempts with assignment update merge and setdefault in Python
Five ways people try to add to a dictionary, and what each one does.

Why dict.append() does not exist

The error is clear about it:

scores = {"ann": 90}

print("does a dictionary have .append()?", hasattr(dict, "append"))
print()

try:
    scores.append("bob")
except AttributeError as err:
    print("scores.append('bob') -> AttributeError:", err)

print()
print("append belongs to lists. A list has positions to add to the end of.")
print("A dictionary has keys, so you say which key you mean.")

Output:

does a dictionary have .append()? False

scores.append('bob') -> AttributeError: 'dict' object has no attribute 'append'

append belongs to lists. A list has positions to add to the end of.
A dictionary has keys, so you say which key you mean.
Command Prompt showing the Python AttributeError that a dict object has no attribute append
.append() is a list method, so a dictionary rejects it.

A list is a sequence, so “append” has an obvious meaning: put this at the end. A dictionary has no end to append to, only keys, so adding always involves naming one.

Add a key and value to a dictionary

Assignment does the job, and also does the updating:

scores = {"ann": 90}

scores["bob"] = 85
scores["cat"] = 95

print("after two assignments ->", scores)
print()
print("that is the whole operation. There is no method to call.")
print()

print("but an existing key OVERWRITES rather than adding:")
scores["ann"] = 100
print("  scores['ann'] = 100 ->", scores)
print("  still", len(scores), "keys")
print()
print("keys are unique, so a dictionary can never hold 'ann' twice.")

Output:

after two assignments -> {'ann': 90, 'bob': 85, 'cat': 95}

that is the whole operation. There is no method to call.

but an existing key OVERWRITES rather than adding:
  scores['ann'] = 100 -> {'ann': 100, 'bob': 85, 'cat': 95}
  still 3 keys

keys are unique, so a dictionary can never hold 'ann' twice.
Command Prompt showing how to add a key and value to a Python dictionary by assignment
scores["bob"] = 85 adds the key; assigning to an existing key replaces it.

That second behaviour catches people out. Assigning to a key that already exists overwrites the value rather than adding a second entry, because keys are unique.

If you need to keep both values, the value has to be a list, which is covered below. To check first, see whether a key exists.

Add several items with update()

update() takes a dictionary, keyword arguments or pairs:

scores = {"ann": 90}

scores.update({"bob": 85, "cat": 95})
print("update with a dictionary ->", scores)

scores.update(dan=70, eve=88)
print("update with keywords     ->", scores)

scores.update([("fay", 60)])
print("update with pairs        ->", scores)
print()
print("update() changes the dictionary in place and returns None,")
print("so never write  scores = scores.update(...)")
result = {"a": 1}.update({"b": 2})
print("  the return value is ->", result)

Output:

update with a dictionary -> {'ann': 90, 'bob': 85, 'cat': 95}
update with keywords     -> {'ann': 90, 'bob': 85, 'cat': 95, 'dan': 70, 'eve': 88}
update with pairs        -> {'ann': 90, 'bob': 85, 'cat': 95, 'dan': 70, 'eve': 88, 'fay': 60}

update() changes the dictionary in place and returns None,
so never write  scores = scores.update(...)
  the return value is -> None

It changes the dictionary in place and returns None. Writing scores = scores.update(...) therefore throws your dictionary away and leaves you with None, which is a memorable afternoon.

Existing keys are overwritten by the incoming values, exactly as single assignment does.

Add one dictionary to another

Three ways to combine, and they differ in what they change:

defaults = {"theme": "light", "size": 12}
user = {"size": 14, "font": "Inter"}

print("defaults ->", defaults)
print("user     ->", user)
print()

print("{**defaults, **user} ->", {**defaults, **user})
print("defaults | user      ->", defaults | user)
print("  the right-hand side wins on 'size'")
print()

print("both leave the originals alone:")
print("  defaults is still ->", defaults)
print()

merged = dict(defaults)
merged |= user
print("|= merges into the left one:")
print("  merged ->", merged)

Output:

defaults -> {'theme': 'light', 'size': 12}
user     -> {'size': 14, 'font': 'Inter'}

{**defaults, **user} -> {'theme': 'light', 'size': 14, 'font': 'Inter'}
defaults | user      -> {'theme': 'light', 'size': 14, 'font': 'Inter'}
  the right-hand side wins on 'size'

both leave the originals alone:
  defaults is still -> {'theme': 'light', 'size': 12}

|= merges into the left one:
  merged -> {'theme': 'light', 'size': 14, 'font': 'Inter'}
Command Prompt showing Python dictionaries merged with the double star syntax and the pipe operator
| and {**a, **b} build a new dictionary; the right-hand side wins.
FormResultOriginals
a.update(b)a is changeda is modified
{**a, **b}A new dictionaryBoth untouched
a | bA new dictionaryBoth untouched
a |= ba is changedSame as update

The | operator arrived in Python 3.9 and reads best. Use the {**a, **b} form if you need to support older versions.

Where both dictionaries hold the same key, the one on the right wins. That is what makes this pattern good for applying user settings over defaults.

Append to a list inside a dictionary

This is the question behind most searches for “dictionary append”:

words = ["ant", "bee", "auk", "bat"]

print("what people usually mean by 'append to a dictionary':")
print("adding to a LIST that is stored as a value.")
print()

print("a plain dictionary cannot do it directly:")
plain = {}
try:
    plain["a"].append("ant")
except KeyError as err:
    print("  plain['a'].append('ant') -> KeyError:", err)
print("  the key does not exist yet, so there is no list to append to")
print()

groups = {}
for word in words:
    groups.setdefault(word[0], []).append(word)
print("setdefault creates the list on first use:")
print("  ", groups)
print()

from collections import defaultdict
auto = defaultdict(list)
for word in words:
    auto[word[0]].append(word)
print("defaultdict(list) does the same with no setdefault:")
print("  ", dict(auto))

Output:

what people usually mean by 'append to a dictionary':
adding to a LIST that is stored as a value.

a plain dictionary cannot do it directly:
  plain['a'].append('ant') -> KeyError: 'a'
  the key does not exist yet, so there is no list to append to

setdefault creates the list on first use:
   {'a': ['ant', 'auk'], 'b': ['bee', 'bat']}

defaultdict(list) does the same with no setdefault:
   {'a': ['ant', 'auk'], 'b': ['bee', 'bat']}
Command Prompt showing how to append to a list stored as a Python dictionary value using setdefault
setdefault(key, []).append(value) creates the list on first use.

A plain dictionary raises KeyError the first time, because there is no list there yet to append to. Something has to create it.

setdefault(key, []) returns the existing list, or inserts an empty one and returns that, so the .append() on the end always has something to work with.

defaultdict(list) removes even that step by building a list automatically for any missing key. Both are worth knowing; defaultdict is cleaner in a loop, setdefault avoids an import. See iterating a dictionary for reading the result back.

Add only if the key is missing

setdefault() on its own is the “do not overwrite” version of assignment:

settings = {"theme": "dark"}

print("setdefault writes only when the key is missing:")
print("  setdefault('theme', 'light') ->", settings.setdefault("theme", "light"))
print("  setdefault('size', 12)       ->", settings.setdefault("size", 12))
print("  settings ->", settings)
print()
print("theme kept its existing value; size was added.")
print()

print("the same idea written out:")
settings = {"theme": "dark"}
if "size" not in settings:
    settings["size"] = 12
print("  ", settings)
print()
print("setdefault returns the value either way, which is what makes")
print("the .append() chain in the previous example work.")

Output:

setdefault writes only when the key is missing:
  setdefault('theme', 'light') -> dark
  setdefault('size', 12)       -> 12
  settings -> {'theme': 'dark', 'size': 12}

theme kept its existing value; size was added.

the same idea written out:
   {'theme': 'dark', 'size': 12}

setdefault returns the value either way, which is what makes
the .append() chain in the previous example work.

It returns the value that ends up in the dictionary, whether that was already there or has just been inserted. The long form with if key not in d does the same and is arguably clearer.

Adding to a nested dictionary

Each level is just another dictionary:

students = {"ann": {"maths": 90}}

students["ann"]["art"] = 70
print("adding to an inner dictionary ->", students)
print()

students.setdefault("bob", {})["maths"] = 60
print("adding a whole new person     ->", students)
print()
print("setdefault({}) creates the inner dictionary when bob is new,")
print("and leaves it alone when he already exists.")
print()

from collections import defaultdict
grid = defaultdict(dict)
grid["row1"]["col1"] = "x"
grid["row2"]["col1"] = "y"
print("defaultdict(dict) for a two level structure:")
print("  ", dict(grid))

Output:

adding to an inner dictionary -> {'ann': {'maths': 90, 'art': 70}}

adding a whole new person     -> {'ann': {'maths': 90, 'art': 70}, 'bob': {'maths': 60}}

setdefault({}) creates the inner dictionary when bob is new,
and leaves it alone when he already exists.

defaultdict(dict) for a two level structure:
   {'row1': {'col1': 'x'}, 'row2': {'col1': 'y'}}

Reaching an inner key needs the outer one to exist already, which is why setdefault("bob", {}) appears. It creates the inner dictionary for a new person and returns the existing one otherwise.

defaultdict(dict) handles two levels without any of that, and nesting defaultdict inside itself handles more.

What can be used as a dictionary key

Not everything is allowed:

print("keys have to be hashable, so a list cannot be one:")
try:
    broken = {}
    broken[["x", "y"]] = 1
except TypeError as err:
    print("  TypeError:", err)

print()
print("a tuple can, because it cannot change:")
print("  ", {("x", "y"): 1})
print()

print("numbers, strings, tuples and booleans are all fine:")
print("  ", {1: "int", "a": "str", (1, 2): "tuple", True: "bool"})
print()
print("watch that last one: True == 1, so they collide as keys.")
print("  {1: 'first', True: 'second'} ->", {1: "first", True: "second"})

Output:

keys have to be hashable, so a list cannot be one:
  TypeError: unhashable type: 'list'

a tuple can, because it cannot change:
   {('x', 'y'): 1}

numbers, strings, tuples and booleans are all fine:
   {1: 'bool', 'a': 'str', (1, 2): 'tuple'}

watch that last one: True == 1, so they collide as keys.
  {1: 'first', True: 'second'} -> {1: 'second'}
Command Prompt showing the Python TypeError unhashable type list when using a list as a dictionary key
A list cannot be a key; a tuple can, because it cannot change.

Keys must be hashable, which in practice means immutable. Strings, numbers and tuples work; lists, dictionaries and sets do not.

The True and 1 collision is worth remembering. They are equal in Python, so a dictionary treats them as the same key.

Building a dictionary from scratch

Several routes, depending on what you are starting from:

names = ["ann", "bob", "cat"]
scores = [90, 85, 95]

print("from two lists:")
print("  dict(zip(names, scores)) ->", dict(zip(names, scores)))
print()

print("in a loop:")
built = {}
for name, score in zip(names, scores):
    built[name] = score
print("  ", built)
print()

print("with a comprehension:")
print("  ", {name: score for name, score in zip(names, scores)})
print()

print("counting as you go:")
counts = {}
for letter in "hello":
    counts[letter] = counts.get(letter, 0) + 1
print("  ", counts)
print("  .get(letter, 0) supplies the starting value, so no KeyError")

Output:

from two lists:
  dict(zip(names, scores)) -> {'ann': 90, 'bob': 85, 'cat': 95}

in a loop:
   {'ann': 90, 'bob': 85, 'cat': 95}

with a comprehension:
   {'ann': 90, 'bob': 85, 'cat': 95}

counting as you go:
   {'h': 1, 'e': 1, 'l': 2, 'o': 1}
  .get(letter, 0) supplies the starting value, so no KeyError

dict(zip(keys, values)) is the shortest when you have two parallel lists. A comprehension is better when the values need transforming on the way in.

The .get(key, 0) pattern in the counting example avoids a KeyError on first sight of each letter. Creating an empty dictionary covers where to start.

Python dictionary append quick reference

  • d[key] = value adds one item, or replaces it if the key exists.
  • d.update(other) adds several and changes d in place.
  • a | b makes a new merged dictionary, with b winning ties.
  • d.setdefault(key, []).append(value) appends to a list value.
  • defaultdict(list) does the same without setdefault.
  • d.setdefault(key, default) alone adds only when the key is missing.
  • Keys must be hashable, so use a tuple rather than a list.

If you are working with dictionaries, these go well alongside:

Frequently asked questions

How do I append to a dictionary in Python?

Assign to a key: my_dict["key"] = value. Dictionaries have no .append() method, since that belongs to lists.

Why does dict.append() give an AttributeError?

Because the method does not exist. The message reads 'dict' object has no attribute 'append'. Use assignment or update() instead.

How do I add multiple items to a dictionary at once?

d.update({"a": 1, "b": 2}). It also accepts keyword arguments and a list of pairs, and it modifies the dictionary in place.

How do I add one dictionary to another?

a | b makes a new merged dictionary in Python 3.9 and later, {**a, **b} works everywhere, and a.update(b) changes a itself.

How do I append a value to a list inside a dictionary?

d.setdefault(key, []).append(value), which creates the list the first time. A defaultdict(list) does it automatically.

Why does adding a key replace the old value?

Because keys are unique. Assigning to an existing key overwrites it. Store a list as the value if you need to keep several items under one key.

Can I use a list as a dictionary key?

No, it raises TypeError: unhashable type: 'list'. Use a tuple instead, as explained in the Python dictionary documentation.