Python中合并含列表的字典时,原字典为何被意外修改?
Let’s break down what’s happening here—this is a classic case of Python’s shallow vs. deep copying catching folks off guard.
The Root Cause: Shallow Copies Don’t Duplicate Mutable Objects
When you use dict.copy() (like you did with dict_b_copy = d_b.copy()), you’re creating a shallow copy of the dictionary. Here’s what that means:
- The dictionary itself is a new object, but the values inside it are just references to the original objects.
- Since lists are mutable (you can change their contents without creating a new list),
dict_b_copy["Item1"]points to the exact same list asd_b["Item1"].
So when you run this line:
dict_b_copy[entry_key].append(list_item)
You’re modifying that shared list directly. That’s why the original dict_b ends up with extra elements—you never actually copied the list itself, just the dictionary holding a reference to it.
Why It Works With Unique Keys
When keys are unique, you add a new entry to dict_b_copy like this:
dict_b_copy[entry_key] = dict_a_copy[entry_key]
Since dict_b doesn’t have that key, there’s no shared reference to a list in the original dictionary. You’re just copying the reference from dict_a_copy to the new dictionary, but since you don’t modify that list, the original dict_a and dict_b stay untouched.
Fixing the Problem
You have two solid options to prevent modifying the original dictionaries:
Option 1: Use Deep Copy
Use Python’s copy.deepcopy() to create a full copy of the dictionary and all mutable objects inside it (like lists):
import copy def combine(d_a, d_b): dict_a_copy = copy.deepcopy(d_a) dict_b_copy = copy.deepcopy(d_b) for entry_key in dict_a_copy: if entry_key in dict_b_copy: dict_b_copy[entry_key].extend(dict_a_copy[entry_key]) else: dict_b_copy[entry_key] = dict_a_copy[entry_key] return dict_b_copy
This ensures every list is a new object, so changes to dict_b_copy won’t affect the original dict_b.
Option 2: Create New Lists When Merging
Instead of modifying the existing list in the shallow copy, create a new list by combining the two:
def combine(d_a, d_b): new_dict = d_b.copy() for entry_key, items in d_a.items(): if entry_key in new_dict: # Create a new list by combining both lists new_dict[entry_key] = new_dict[entry_key] + items else: new_dict[entry_key] = items.copy() # Copy the list to avoid referencing dict_a's list return new_dict
Here, new_dict[entry_key] = new_dict[entry_key] + items creates a brand new list, so the original list in d_b stays untouched. We also copy the list from d_a when adding new entries to avoid accidentally modifying dict_a later.
Either approach will give you the expected output where dict_a and dict_b remain unchanged, and dict_ab has the combined lists.
内容的提问来源于stack exchange,提问作者Iain Waugh




