Python dict update: Merging and Modifying Dictionaries
python dict update: Learn how to use Python's dict.update() to merge dictionaries, modify keys in place, and handle edge cases efficiently.
python dict update requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
Python's dict.update() method is the standard way to merge another mapping or an iterable of key-value pairs into an existing dictionary. It modifies the dictionary in place, adding new keys and overwriting existing ones. This method is central to many data-processing tasks, yet its behavior and performance implications are often misunderstood. This article explains how update() works, when to use it, and what to watch out for.
What dict.update() Does
The update() method accepts either a dictionary, an iterable of key-value pairs, or keyword arguments. When called, it iterates over the provided data and assigns each key to the dictionary, replacing any existing value for that key. The method returns None, which is a common source of bugs when developers expect a new dictionary.
config = {"host": "localhost", "port": 8080} config.update({"port": 9090, "debug": True}) print(config) # {'host': 'localhost', 'port': 9090, 'debug': True}
Here, the port key is overwritten, and debug is added. The original dictionary object is mutated; no new dictionary is created.
Updating from Another Dictionary or Iterable
The most common use is passing another dictionary to update(). However, the method also accepts any iterable that yields key-value pairs, such as a list of tuples or a generator. This flexibility is useful when you have data in a non-dictionary format.
pairs = [("a", 1), ("b", 2)] d = {} d.update(pairs) print(d) # {'a': 1, 'b': 2}
When the iterable contains items that are not two-element sequences, update() raises a ValueError. For example, d.update([1, 2]) fails because integers are not unpackable. This behavior is consistent with the expectation that each item represents a key-value pair.
In-Place Mutation and Return Value
Because update() modifies the dictionary in place, it returns None. A common mistake is chaining update() calls or assigning its result to a variable. The following code does not create a merged dictionary:
a = {"x": 1} b = a.update({"y": 2}) print(b) # None
If you need a new dictionary that includes the updates, create a copy first or use dictionary unpacking (see the alternatives section). In-place mutation is efficient for incremental updates, but it changes the original object, which may have unintended side effects if the dictionary is shared across multiple parts of a program.
Overwriting Behavior and Merge Semantics
update() overwrites existing keys with the values from the source. This is the expected behavior for merging configuration or state. The method does not merge nested dictionaries recursively; it replaces the entire value for a key. For example:
base = {"db": {"host": "localhost", "port": 5432}} override = {"db": {"user": "admin"}} base.update(override) print(base) # {'db': {'user': 'admin'}}
The db key is replaced entirely, not merged. If you need deep merging, you must implement it manually or use a library. This is a critical distinction when working with nested configuration structures.
Using update() with Keyword Arguments
update() also accepts keyword arguments, which are treated as key-value pairs. This is convenient for small updates, but it imposes a constraint: keys must be valid Python identifiers because they are passed as keyword arguments. String keys with spaces or hyphens cannot be used this way.
settings = {} settings.update(timeout=30, retries=3) print(settings) # {'timeout': 30, 'retries': 3}
This syntax is equivalent to passing a dictionary with those keys. It is useful when the keys are known at code-writing time and are simple identifiers. For dynamic keys, use a dictionary or iterable instead.
Performance: In-Place vs. Creating a New Dictionary
update() is an in-place operation, so it does not allocate a new dictionary. This makes it more memory-efficient than creating a new dictionary and copying entries, especially when updating a large dictionary repeatedly. However, the source data still needs to be iterated, and each key assignment has a cost. If you are updating a dictionary in a loop, update() avoids the overhead of creating intermediate dictionaries.
result = {} for item in items: result.update(item)
In contrast, using dictionary unpacking to create a new dictionary each iteration would allocate a new object and copy all previous entries, leading to O(n^2) time. For incremental accumulation, update() is the appropriate choice. When you need to preserve the original dictionary and produce a new one, copying first is necessary, but that copy adds memory and CPU overhead.
Common Edge Cases and Mistakes
One frequent mistake is updating a dictionary while iterating over it. Since update() can add new keys, iterating over the dictionary and updating it may cause a RuntimeError if the dictionary size changes during iteration. If you need to conditionally update based on existing keys, iterate over a copy of the keys first.
Another edge case is using update() with a default dictionary or a custom mapping. The method works with any object that has a keys() method and supports iteration over key-value pairs, but the exact behavior depends on the implementation. For example, collections.defaultdict updates normally, but the default factory is not triggered by update(); it only applies when a missing key is accessed.
Finally, be aware that update() accepts an iterable of key-value pairs, but if the iterable is a string, it will be treated as a sequence of characters, causing a ValueError because each character is not a pair. This is a common mistake when accidentally passing a string instead of a mapping.
Alternatives to update(): Merging with | and Unpacking
Python 3.9 introduced the | operator for merging dictionaries, which creates a new dictionary without modifying the original. This is useful when you need a non-destructive merge.
a = {"x": 1} b = {"y": 2} merged = a | b print(merged) # {'x': 1, 'y': 2} print(a) # {'x': 1} (unchanged)
Similarly, dictionary unpacking with ** can merge multiple dictionaries into a new one, but it is less readable when merging more than two. The | operator is more explicit and supports in-place merging with |=.
The choice between update() and | depends on whether you need to mutate the original dictionary. update() is the right tool when you are building a dictionary incrementally or when you want to modify an existing object. The | operator is better when you need a merged copy and want to keep the inputs unchanged. For most code, update() remains the standard method because it works in all Python 3 versions and is widely understood.