Repository navigation
Expand file tree
/
Copy pathdict_union.py
More file actions
115 lines (92 loc) 路 4.02 KB
/
Copy pathdict_union.py
File metadata and controls
115 lines (92 loc) 路 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""
Dictionary union operators (`|` and `|=`, introduced in Python 3.9 via PEP 584)
provide clean syntax for merging dictionaries.
The binary operator `|` creates a new dictionary combining keys and values from
both operands without mutating either one. The in-place operator `|=` updates the
left-hand dictionary in place. When duplicate keys exist, the right-hand operand's
value takes precedence.
"""
from typing import Any
def cascade_config(base: dict[str, Any], *overrides: dict[str, Any]) -> dict[str, Any]:
"""Cascade configuration layers without mutating input dictionaries.
Later layers override earlier ones, returning a freshly merged dictionary.
"""
merged = base.copy()
for override in overrides:
merged |= override
return merged
def apply_patch(record: dict[str, Any], patch: dict[str, Any]) -> None:
"""Apply a partial update in-place to an existing record using |=."""
record |= patch
def main() -> None:
# 1. Non-mutating dictionary union (|)
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
merged = dict1 | dict2
assert merged == {"a": 1, "b": 2, "c": 3, "d": 4}
# Original dictionaries remain untouched
assert dict1 == {"a": 1, "b": 2}
assert dict2 == {"c": 3, "d": 4}
# 2. Overlapping key precedence: right operand overrides left operand
dict3 = {"a": 1, "b": 2, "c": 3}
dict4 = {"b": 20, "c": 30, "d": 4}
merged2 = dict3 | dict4
assert merged2 == {"a": 1, "b": 20, "c": 30, "d": 4}
# Order matters: left is the base, right is the override
merged3 = dict4 | dict3
assert merged3 == {"b": 2, "c": 3, "d": 4, "a": 1}
# 3. In-place dictionary union (|=)
# Mutates the left operand in place, leaving the right operand unchanged
dict5 = {"a": 1, "b": 2}
dict6 = {"b": 20, "c": 3}
dict5 |= dict6
assert dict5 == {"a": 1, "b": 20, "c": 3}
assert dict6 == {"b": 20, "c": 3}
# 4. Chained unions
dict_a = {"x": 1}
dict_b = {"y": 2}
dict_c = {"z": 3, "x": 10}
combined = dict_a | dict_b | dict_c
assert combined == {"x": 10, "y": 2, "z": 3}
# 5. Empty dictionaries and dict() constructors
empty: dict[str, int] = {}
assert empty | {"a": 1} == {"a": 1}
assert dict(a=1, b=2) | dict(c=3) == {"a": 1, "b": 2, "c": 3}
# 6. Practical engineering: Cascading configuration layers
default_config = {"timeout": 30, "retries": 3, "debug": False, "log_level": "INFO"}
env_config = {"debug": True}
cli_config = {"timeout": 60, "log_level": "DEBUG"}
active_config = cascade_config(default_config, env_config, cli_config)
assert active_config == {
"timeout": 60, # Overridden by CLI
"retries": 3, # Retained from defaults
"debug": True, # Overridden by environment
"log_level": "DEBUG", # Overridden by CLI
}
# Verified: default_config was never mutated
assert default_config["timeout"] == 30
assert default_config["debug"] is False
# 7. Practical engineering: Applying in-place record patches
user_record = {"id": 100, "name": "Jane", "status": "active", "login_count": 5}
patch_data = {"status": "inactive", "login_count": 6}
apply_patch(user_record, patch_data)
assert user_record == {"id": 100, "name": "Jane", "status": "inactive", "login_count": 6}
# 8. Type safety: Unions require both operands to be dict instances
error_raised = False
try:
dict1 | [("c", 3)] # type: ignore [operator]
except TypeError:
error_raised = True
assert error_raised is True
# Non-dict compatible mappings must be converted explicitly
assert dict1 | dict([("c", 3)]) == {"a": 1, "b": 2, "c": 3}
# 9. Comparison with pre-3.9 approaches
# Traditional update() mutated in place and returned None (no chaining):
legacy_dict = {"a": 1}
legacy_dict.update({"b": 2})
assert legacy_dict == {"a": 1, "b": 2}
# Traditional unpacking syntax was verbose:
legacy_unpacking = {**{"a": 1}, **{"b": 2}}
assert legacy_unpacking == {"a": 1, "b": 2}
if __name__ == "__main__":
main()