Python
Dictionary
Concatenation
Coding
Programming

How to concatenate two dictionaries to create a new one?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Combining dictionaries in Python is simple for flat key-value pairs, but details matter when keys overlap or values are nested. The wrong merge method can silently overwrite data or mutate objects you expected to keep unchanged. This guide compares reliable merge patterns and when to use each one.

Use the Merge Operator for Readable New Dictionaries

In modern Python, the | operator creates a new dictionary from two inputs. If both dictionaries contain the same key, the right-hand dictionary wins.

python
1left = {"host": "localhost", "port": 5432, "ssl": False}
2right = {"port": 5433, "timeout": 30}
3
4merged = left | right
5
6print("left:", left)
7print("right:", right)
8print("merged:", merged)

Output behavior:

  • left and right remain unchanged.
  • merged["port"] becomes 5433 because right side overrides left side.

This is usually the cleanest syntax for configuration layering, such as defaults plus environment-specific overrides.

Support Older Python With Unpacking

If you need compatibility with Python 3.5 and later, dictionary unpacking provides similar behavior.

python
1defaults = {"retries": 3, "backoff": 1.0}
2override = {"backoff": 2.5}
3
4merged = {**defaults, **override}
5print(merged)

Unpacking creates a new dictionary and follows the same key precedence rule where later values override earlier ones.

For dynamic multi-source merges, combine many dictionaries in order:

python
1base = {"log_level": "INFO", "region": "us-east-1"}
2team = {"log_level": "DEBUG"}
3user = {"region": "ca-central-1"}
4
5merged = {**base, **team, **user}
6print(merged)

The final result reflects the last value for each repeated key.

Use copy Plus update When You Need In-Place Flow

update mutates a dictionary, which can be efficient in imperative pipelines. If you still need a new dictionary, clone first.

python
1source_a = {"a": 1, "b": 2}
2source_b = {"b": 20, "c": 30}
3
4result = source_a.copy()
5result.update(source_b)
6
7print("source_a:", source_a)
8print("result:", result)

This style is explicit in multi-step code where you progressively enrich one working object. It is also convenient when merge inputs are produced conditionally.

Handle Nested Dictionaries With Deep Merge Logic

All basic merge methods are shallow. If both sides contain nested dictionaries under the same key, the entire nested object from the right side replaces the left side value.

When you need recursive behavior, implement a deep merge function:

python
1from copy import deepcopy
2
3
4def deep_merge(left: dict, right: dict) -> dict:
5    result = deepcopy(left)
6    for key, value in right.items():
7        if (
8            key in result
9            and isinstance(result[key], dict)
10            and isinstance(value, dict)
11        ):
12            result[key] = deep_merge(result[key], value)
13        else:
14            result[key] = deepcopy(value)
15    return result
16
17
18if __name__ == "__main__":
19    a = {
20        "db": {"host": "localhost", "pool": {"min": 2, "max": 10}},
21        "feature": {"enabled": False},
22    }
23    b = {
24        "db": {"pool": {"max": 30}},
25        "feature": {"enabled": True},
26    }
27
28    merged = deep_merge(a, b)
29    print(merged)

This approach protects nested data and avoids mutation side effects through deep copies.

Choose Merge Semantics Deliberately

Before choosing syntax, define merge rules clearly:

  • should right side always override
  • should missing keys be preserved
  • should nested dictionaries merge recursively
  • should lists append, replace, or deduplicate

Encoding these rules in one utility function prevents inconsistent behavior across modules.

For application configuration, merge order should mirror precedence levels. For example: defaults, environment file, secret store, runtime flags. Keeping this order explicit improves predictability and debugging.

Common Pitfalls

  • Assuming merges are deep when Python built-in merge methods are shallow.
  • Mutating a source dictionary with update when immutable behavior was expected.
  • Relying on implicit key precedence instead of documenting source priority.
  • Merging dictionaries that contain mutable nested structures without copying.
  • Forgetting version compatibility when using the | operator on older Python versions.

Summary

  • Use | for clear new-dictionary merges in modern Python.
  • Use unpacking syntax for broad Python 3 compatibility.
  • Use copy plus update for explicit stepwise mutation workflows.
  • Implement deep merge when nested dictionary values must combine recursively.
  • Define and document precedence rules to avoid silent data loss.

Course illustration
Course illustration

All Rights Reserved.