Back to Blog
Python

Python Dictionary Add Item: Methods and Tradeoffs

python dictionary add item: Learn how to add items to Python dictionaries using assignment, update(), setdefault(), and merging, with practical tradeoffs.

dictionarypython syntaxdata structuresupdate methodsetdefaultdict merging
Illustration of adding a key-value pair to a Python dictionary with a plus symbol.

When you need to add an item to a Python dictionary, the most direct approach is assignment: d[key] = value. This works for new keys and overwrites existing ones. But depending on whether you're adding one item, many items, or merging from another dictionary, other methods like update(), setdefault(), or the | operator may be more appropriate. This article covers the practical ways to perform a python dictionary add item operation, the behavior of each approach, and the tradeoffs that matter in real code.

Basic Assignment and Key Collision Behavior

The simplest way to add a key-value pair is direct assignment:

config = {} config["host"] = "localhost" config["port"] = 8080

If the key already exists, assignment replaces the old value. That is usually what you want when updating a configuration value. But if you need to preserve the original value and only add when the key is absent, assignment is the wrong tool because it silently overwrites.

settings = {"theme": "dark"} settings["theme"] = "light" # overwrites

For conditional insertion, you need a method that checks existence first, which we'll cover shortly.

Using update() to Add Multiple Items

When you have several key-value pairs to add at once, update() accepts a dictionary, an iterable of key-value tuples, or keyword arguments.

server = {"host": "example.com"} server.update({"port": 443, "tls": True}) # or server.update([("port", 443), ("tls", True)]) # or server.update(port=443, tls=True)

update() also overwrites existing keys. It is a single call, which is more readable than multiple assignments when the number of keys is moderate. It does not return the dictionary; it modifies in place and returns None.

One subtle point: if you pass keyword arguments, the keys must be valid Python identifiers. That means "server-port" cannot be used as a keyword argument, but it can be a string key in a dictionary or tuple list.

setdefault() for Conditional Insertion

setdefault(key, default) returns the current value if the key exists; otherwise it inserts the key with the default value and returns that default. This is useful for building counters or accumulating data without an explicit if check.

occurrences = {} for word in ["apple", "banana", "apple"]: occurrences.setdefault(word, 0) occurrences[word] += 1

A more concise pattern uses setdefault to initialize a list before appending:

groups = {} for item in [("a", 1), ("b", 2), ("a", 3)]: groups.setdefault(item[0], []).append(item[1])

setdefault is not atomic under concurrency. If you have multiple threads modifying the same dictionary, you still need a lock or a different data structure. Also, the default argument is evaluated eagerly, even if the key exists. So setdefault(key, expensive_function()) always calls expensive_function(), which may be a performance concern.

Merging Dictionaries with | and **

Python 3.9 introduced the union operator | for dictionaries, which returns a new dictionary that combines two existing ones. The right-hand dictionary takes precedence for overlapping keys.

defaults = {"timeout": 30, "retries": 3} user = {"timeout": 60} merged = defaults | user # {'timeout': 60, 'retries': 3}

There is also the augmented assignment |= which updates the left-hand dictionary in place:

defaults |= user

Before 3.9, the common idiom was {**a, **b}. Both approaches create a new dictionary for |, while |= mutates the left operand. If you need to preserve the original dictionaries, | is cleaner. If you are merging in a loop, |= avoids repeated copying.

Adding Items in Loops and Comprehensions

When building a dictionary from a sequence, a comprehension is often more readable than a loop with assignment.

squares = {x: x**2 for x in range(10)}

For more complex logic, a loop with direct assignment is fine. The key is to avoid calling update() in every iteration unless you have a batch of pairs to add at once.

result = {} for key, value in raw_data: result[key] = transform(value)

A common mistake is to use dict.fromkeys() with a mutable default value, which shares the same object across all keys:

# Wrong: all keys share the same list bad = dict.fromkeys(["a", "b"], []) bad["a"].append(1) # bad["b"] also gets 1

Use a comprehension or setdefault when each key needs a distinct mutable value.

Performance and Memory Considerations

Adding items to a dictionary is amortized O(1) on average, but there are practical differences between methods. Direct assignment is the fastest for a single item because it avoids a function call. update() is efficient for multiple items because it processes them in one C-level loop. setdefault involves an extra lookup and a function call, so it is slightly slower than a direct if key not in dict check followed by assignment, but the difference is usually negligible unless you are doing millions of operations.

Memory usage is more subtle. Each dictionary entry stores a hash, a key reference, and a value reference. When you add many items, the dictionary may need to resize its internal hash table, which temporarily doubles memory usage. If you know the final size in advance, you can pre-allocate with dict.fromkeys or by constructing a dictionary from a known-size iterable, but this is rarely necessary unless memory is tight.

For long-running processes, be aware that update() with a large dictionary copies references, not the objects themselves. If you merge a large dictionary into another, the original keys and values are not duplicated, only the references. This is usually fine, but if you later modify the original dictionary, the merged dictionary will not see those changes.

Choosing the Right Method for Your Use Case

The decision among these methods comes down to what you need:

MethodUse caseBehavior on existing key
d[key] = valueSingle item, overwrite allowedOverwrites
d.update(...)Multiple items, overwrite allowedOverwrites
d.setdefault(key, default)Add only if missingKeeps existing value
`d1d2`Merge into new dict, right wins
`d1= d2`Merge into existing dict

If you are adding a single item and want to avoid overwriting an existing value, use setdefault or an explicit if key not in d check. The explicit check is more readable when the default value is expensive to compute:

if key not in d: d[key] = expensive_default()

If you are merging two dictionaries and need to preserve the original, use |. If you are building a dictionary incrementally in a loop and the number of items is dynamic, direct assignment is clear and efficient. If you find yourself writing repeated if checks for the same key, consider setdefault or a defaultdict from the collections module, which provides a more elegant way to handle missing keys.

A final note on compatibility: the | operator requires Python 3.9 or later. If your code must run on earlier versions, use {**a, **b} or dict(a, **b) for merging. The latter works but only accepts string keys for the keyword arguments. For maximum compatibility and clarity, {**a, **b} is the safest pre-3.9 approach.

python dictionary add item: Practical Usage and Code Example | RYUSLOG DEV