Merge two dictionaries recursively into the first one. Example: >>> d1 = {'dict': {'a': 1}, 'list': [1, 2], 'tuple': (1, 2)} >>> d2 = {'dict': {'b': 2}, 'list': [3, 4], 'set': {'a', 'b'}} >>> _merge_dictionaries(d1, d2) d1 will be modified to: { 'dict': {'a': 1, 'b': 2}
(d1, d2, aggregate_duplicates=True)
| 71 | |
| 72 | |
| 73 | def _merge_dictionaries(d1, d2, aggregate_duplicates=True): |
| 74 | """Merge two dictionaries recursively into the first one. |
| 75 | |
| 76 | Example: |
| 77 | >>> d1 = {'dict': {'a': 1}, 'list': [1, 2], 'tuple': (1, 2)} |
| 78 | >>> d2 = {'dict': {'b': 2}, 'list': [3, 4], 'set': {'a', 'b'}} |
| 79 | >>> _merge_dictionaries(d1, d2) |
| 80 | |
| 81 | d1 will be modified to: { |
| 82 | 'dict': {'a': 1, 'b': 2}, |
| 83 | 'list': [1, 2, 3, 4], |
| 84 | 'tuple': (1, 2), |
| 85 | 'set': {'a', 'b'} |
| 86 | } |
| 87 | |
| 88 | Arguments: |
| 89 | d1 (dict): Dictionary to merge into. |
| 90 | d2 (dict): Dictionary to merge from. |
| 91 | aggregate_duplicates (bool): |
| 92 | If True, aggregate duplicated items (by key) into a list of all values in d1 in the same key. |
| 93 | If False, duplicate keys will be taken from d2 and override the value in d1. |
| 94 | """ |
| 95 | if not d2: |
| 96 | return |
| 97 | |
| 98 | for key, value in d1.items(): |
| 99 | if key in d2: |
| 100 | if isinstance(value, dict): |
| 101 | _merge_dictionaries(d1[key], d2[key]) |
| 102 | else: |
| 103 | if isinstance(value, (int, float, str)): |
| 104 | d1[key] = [value] if aggregate_duplicates else value |
| 105 | if isinstance(d2[key], list) and isinstance(d1[key], list): |
| 106 | d1[key].extend(d2[key]) |
| 107 | elif aggregate_duplicates: |
| 108 | if d1[key] is None: |
| 109 | d1[key] = [] |
| 110 | else: |
| 111 | d1[key] = list(d1[key]) |
| 112 | d1[key].append(d2[key]) |
| 113 | for key, value in d2.items(): |
| 114 | if key not in d1: |
| 115 | d1[key] = value |
| 116 | |
| 117 | |
| 118 | class StampingVisitor(metaclass=ABCMeta): |