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.
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.
.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.
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'}
| and {**a, **b} build a new dictionary; the right-hand side wins.| Form | Result | Originals |
|---|---|---|
a.update(b) | a is changed | a is modified |
{**a, **b} | A new dictionary | Both untouched |
a | b | A new dictionary | Both untouched |
a |= b | a is changed | Same 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']}
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'}
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] = valueadds one item, or replaces it if the key exists.d.update(other)adds several and changesdin place.a | bmakes a new merged dictionary, withbwinning ties.d.setdefault(key, []).append(value)appends to a list value.defaultdict(list)does the same withoutsetdefault.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:
- Iterate through a dictionary
- Check if a key exists
- Create an empty dictionary
- Check if a dictionary is empty
- Get the keys of a dictionary
- Count the keys in a dictionary
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.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn