@@ -28,8 +28,16 @@ def deep_merge(*dcts: Mapping[str, Any]) -> dict[str, Any]:
2828 if not dcts :
2929 return {}
3030
31+ # Initial deep copy of the base dictionary
3132 result = deepcopy (dict (dcts [0 ]))
3233
34+ # Handlers for specific types (excluding Mapping which needs special handling)
35+ funcmap = {
36+ (list , list ): lambda e , v : e + deepcopy (v ),
37+ (tuple , tuple ): lambda e , v : e + deepcopy (v ),
38+ (set , set ): lambda e , v : e | deepcopy (v ),
39+ }
40+
3341 for src in dcts [1 :]:
3442 stack : list [tuple [dict [str , Any ], Mapping [str , Any ]]] = [(result , src )]
3543
@@ -43,26 +51,19 @@ def deep_merge(*dcts: Mapping[str, Any]) -> dict[str, Any]:
4351
4452 existing = dest [key ]
4553
46- # Mapping → merge deeper
54+ # Special handling for Mappings (recursive merge)
4755 if isinstance (existing , Mapping ) and isinstance (value , Mapping ):
48- # Ensure we are working with a dict for the merge target
49- # This avoids nested specialized types if they support item assignment
5056 if type (existing ) is not dict :
5157 existing = dict (existing )
5258 dest [key ] = existing
5359 stack .append ((existing , value ))
60+ continue
5461
55- # Lists / tuples → concatenate
56- elif (isinstance (existing , list ) and isinstance (value , list )) or (
57- isinstance (existing , tuple ) and isinstance (value , tuple )
58- ):
59- dest [key ] = existing + deepcopy (value ) # type: ignore[operator]
60-
61- # Sets → union
62- elif isinstance (existing , set ) and isinstance (value , set ):
63- dest [key ] = existing | deepcopy (value )
64-
65- # Fallback → overwrite
62+ # Use funcmap for other types
63+ # Using get() on dict with tuple key avoids the loop
64+ handler = funcmap .get ((type (existing ), type (value )))
65+ if handler :
66+ dest [key ] = handler (existing , value )
6667 else :
6768 dest [key ] = deepcopy (value )
6869
0 commit comments