Trong Python, khi làm việc với các cấu trúc dữ liệu phức tạp, việc sao chép (copy) có thể dẫn đến những kết quả không như mong đợi nếu không hiểu rõ về hai khái niệm: Shallow Copy (sao chép nông) và Deep Copy (sao chép sâu). Hiểu rõ sự khác biệt giữa chúng là cực kỳ quan trọng để tránh các lỗi tiềm ẩn và quản lý bộ nhớ hiệu quả.
Shallow Copy (Sao chép nông) tạo ra một đối tượng mới, nhưng các đối tượng lồng nhau bên trong vẫn giữ lại tham chiếu ban đầu. Điều này có nghĩa là, nếu bạn thay đổi một phần tử trong cấu trúc dữ liệu lồng nhau của đối tượng gốc, nó sẽ ảnh hưởng đến cả đối tượng được sao chép nông.
Deep Copy (Sao chép sâu), ngược lại, tạo ra một bản sao hoàn toàn độc lập. Nó sẽ sao chép đệ quy tất cả các đối tượng lồng nhau, đảm bảo rằng bản sao và đối tượng gốc hoàn toàn tách biệt. Bất kỳ thay đổi nào trên một trong hai đối tượng đều không ảnh hưởng đến đối tượng còn lại.
Hãy xem một ví dụ cụ thể để làm rõ sự khác biệt này.
import copy
# Dữ liệu gốc, một từ điển chứa danh sách lồng nhau
original_data = {
'id': 101,
'name': 'Product A',
'details': ['size: M', 'color: blue']
}
# Thực hiện shallow copy
shallow_copied = copy.copy(original_data)
# Thực hiện deep copy
deep_copied = copy.deepcopy(original_data)
# In ra để kiểm tra
print("Original:", original_data)
print("Shallow Copy:", shallow_copied)
print("Deep Copy:", deep_copied)
# Thay đổi dữ liệu gốc
original_data['id'] = 202
original_data['details'].append('material: cotton')
print("
Sau khi thay đổi dữ liệu gốc:")
print("Original:", original_data)
print("Shallow Copy:", shallow_copied)
print("Deep Copy:", deep_copied)
Kết quả đầu ra:
Original: {'id': 101, 'name': 'Product A', 'details': ['size: M', 'color: blue']}
Shallow Copy: {'id': 101, 'name': 'Product A', 'details': ['size: M', 'color: blue']}
Deep Copy: {'id': 101, 'name': 'Product A', 'details': ['size: M', 'color: blue']}
Sau khi thay đổi dữ liệu gốc:
Original: {'id': 202, 'name': 'Product A', 'details': ['size: M', 'color: blue', 'material: cotton']}
Shallow Copy: {'id': 101, 'name': 'Product A', 'details': ['size: M', 'color: blue', 'material: cotton']}
Deep Copy: {'id': 101, 'name': 'Product A', 'details': ['size: M', 'color: blue']}
Phân tích kết quả:
- Shallow Copy:
- Khi chúng ta thay đổi giá trị của khóa
idtrongoriginal_data,shallow_copiedkhông bị ảnh hưởng vìidlà một khóa ở cấp độ cao và được sao chép giá trị. - Tuy nhiên, khi chúng ta thêm một phần tử vào danh sách
details(một cấu trúc lồng nhau),shallow_copiedcũng bị thay đổi. Điều này xảy ra vìshallow_copiedvàoriginal_datađang cùng tham chiếu đến cùng một đối tượng danh sáchdetails.
- Deep Copy:
deep_copiedhoàn toàn không bị ảnh hưởng bởi bất kỳ thay đổi nào trênoriginal_data. Cả khóaidvà danh sáchdetailstrongdeep_copiedđều là các bản sao hoàn toàn mới và độc lập.
Tóm lại, sự khác biệt cốt lõi là:
- Shallow Copy sao chép đối tượng ở cấp độ cao nhất và chia sẻ tham chiếu cho các đối tượng lồng nhau.
- Deep Copy sao chép toàn bộ cấu trúc, bao gồm cả các đối tượng lồng nhau, tạo ra các bản sao hoàn toàn riêng biệt.
Khi nào nên dùng Shallow Copy và Deep Copy?
- Shallow Copy: Thường được sử dụng khi bạn muốn tạo một bản sao nhanh chóng và bạn chắc chắn rằng các đối tượng lồng nhau sẽ không bị thay đổi, hoặc bạn muốn chúng được chia sẻ. Nó hiệu quả hơn về mặt hiệu năng vì không cần sao chép toàn bộ cấu trúc.
- Deep Copy: Cần thiết khi bạn cần một bản sao hoàn toàn độc lập, đặc biệt là khi làm việc với các cấu trúc dữ liệu phức tạp và bạn muốn đảm bảo rằng các thay đổi trên một bản sao không ảnh hưởng đến bản gốc. Ví dụ, khi lưu trữ trạng thái của một đối tượng, hoặc khi truyền dữ liệu qua các hàm mà không sợ bị thay đổi ngoài ý muốn.
Câu hỏi phỏng vấn: Python có sự khác biệt gì giữa Shallow Copy và Deep Copy? Cho một ví dụ.
Câu trả lời của bạn có thể như sau:
"Shallow Copy và Deep Copy khác nhau ở cách chúng xử lý các đối tượng lồng nhau. Shallow Copy chỉ tạo một đối tượng mới ở cấp độ cao nhất, trong khi các đối tượng bên trong vẫn giữ lại tham chiếu ban đầu. Điều này có nghĩa là nếu bạn thay đổi nội dung của một đối tượng lồng nhau, cả đối tượng gốc và đối tượng được sao chép nông đều sẽ bị ảnh hưởng. Ngược lại, Deep Copy sẽ sao chép đệ quy toàn bộ cấu trúc, tạo ra các bản sao hoàn toàn độc lập cho cả đối tượng gốc và các đối tượng lồng nhau, do đó chúng không ảnh hưởng lẫn nhau.
Ví dụ, hãy xem xét một từ điển chứa một danh sách lồng nhau:
import copy
original = {'key': [1, 2, 3]}
shallow = copy.copy(original)
deep = copy.deepcopy(original)
original['key'].append(4)
print(original) # {'key': [1, 2, 3, 4]}
print(shallow) # {'key': [1, 2, 3, 4]} -- bị ảnh hưởng
print(deep) # {'key': [1, 2, 3]} -- không bị ảnh hưởng
Tóm lại, hãy dùng Shallow Copy khi bạn muốn chia sẻ các đối tượng lồng nhau, và dùng Deep Copy khi bạn cần các bản sao hoàn toàn độc lập."