깊은 복사와 얕은 복사는 프로그래밍에서 일반적으로 발생하는 객체 복사에 관한 개념입니다. 객체를 복사할 때, 두 가지 복사 방법인 깊은 복사와 얕은 복사가 있습니다. 이번 글에서는 깊은 복사와 얕은 복사의 개념과 각각의 사용 사례에 대해서 알아보겠습니다. 또한, 자바스크립트와 파이썬을 예시로 들어 각각의 언어에서 구체적인 코드와 함께 비교해보겠습니다.
깊은 복사(Deep Copy)란?
깊은 복사(Deep Copy)란, 복사되는 객체와 새롭게 생성된 객체가 메모리 상에서 서로 다른 곳을 가리키도록 하는 방식입니다. 이는 객체를 복사할 때, 원본 객체의 내부적인 참조를 통해 생성된 객체가 또 다른 객체와 같은 주소를 참조하는 것을 방지합니다. 즉, 깊은 복사를 통해 객체는 서로 독립적이고 원본 객체가 변경되어도 복사된 객체는 영향을 받지 않습니다.
얕은 복사(Shallow Copy)란?
얕은 복사(Shallow Copy)란, 복사되는 객체와 새롭게 생성된 객체가 메모리 상에서 같은 공간을 가리키도록 하는 방식입니다. 따라서, 객체를 복사할 때, 원본 객체의 내부적인 참조와 새로운 객체의 내부 구조 등을 동일하게 유지합니다. 이는 원본 객체와 복사된 객체가 동일한 참조를 가리키므로, 일부의 객체가 같은 값을 가지더라도 그 외의 다른 객체는 독립적입니다.
자바스크립트 예시 코드
깊은 복사(Deep Copy)
const obj1 = { name: 'John', age: 30, hobbies: ['reading', 'walking', 'cooking'] }; const obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj1); // {name: "John", age: 30, hobbies: Array(3)} console.log(obj2); // {name: "John", age: 30, hobbies: Array(3)} obj2.hobbies.push('swimming'); console.log(obj1); // {name: "John", age: 30, hobbies: Array(3)} console.log(obj2); // {name: "John", age: 30, hobbies: Array(4)} |
위 코드에서 obj1 객체를 obj2에 깊은 복사를 수행하여 복사했습니다. 이는 JSON.stringify()와 JSON.parse()를 사용하여 객체를 복사합니다. 따라서, 복사된 객체는 원본 객체와 다른 주소에 위치하게 됩니다.
얕은 복사(Shallow Copy)
const obj1 = { name: 'John', age: 30, hobbies: ['reading', 'walking', 'cooking'] }; const obj2 = obj1; console.log(obj1); // {name: "John", age: 30, hobbies: Array(3)} console.log(obj2); // {name: "John", age: 30, hobbies: Array(3)} obj2.hobbies.push('swimming'); console.log(obj1); // {name: "John", age: 30, hobbies: Array(4)} console.log(obj2); // {name: "John", age: 30, hobbies: Array(4)} |
위 코드에서 obj1 객체를 obj2에 얕은 복사를 수행하여 복사했습니다. 이는 변수에 객체를 할당하는 것만으로도 복사됩니다. 따라서, 복사된 객체와 원본 객체는 동일한 참조를 가리키므로, 일부 값이 같은 경우에는 동일한 참조를 가진 상태에서 변경되게 됩니다.
파이썬 예시 코드
깊은 복사(Deep Copy)
import copy list1 = [1, 2, [3, 4]] list2 = copy.deepcopy(list1) print(list1) # [1, 2, [3, 4]] print(list2) # [1, 2, [3, 4]] list2[2].append(5) print(list1) # [1, 2, [3, 4]] print(list2) # [1, 2, [3, 4, 5]] |
위 코드에서 deepcopy() 함수를 사용하여 list1 객체를 list2 변수에 깊은 복사하였습니다. 이는 내부적으로 객체의 내용 전체를 복사하기 때문에, 복사된 객체와 원본 객체는 완전히 독립적인 상태가 됩니다.
얕은 복사(Shallow Copy)
list1 = [1, 2, [3, 4]] list2 = list1.copy() print(list1) # [1, 2, [3, 4]] print(list2) # [1, 2, [3, 4]] list2[2].append(5) print(list1) # [1, 2, [3, 4, 5]] print(list2) # [1, 2, [3, 4, 5]] |
위 코드에서 copy() 함수를 사용하여 list1 객체를 list2 변수에 얕은 복사하였습니다. 이는 객체 자체는 서로 다른 객체이지만, 객체 내부의 참조는 동일하기 때문에, 일부의 객체만 수정되었을 경우에는 서로에게 영향을 미치게 됩니다.
결론
객체를 복사할 때 깊은 복사와 얕은 복사 방식은 모두 부적절한 사용을 하면 예상치 못한 문제들을 초래할 수 있습니다. 깊은 복사는 원본 객체가 수정되더라도 복사된 객체는 독립적으로 유지할 수 있습니다. 하지만, 객체의 깊이가 매우 깊거나 재귀적인 속성을 가진 경우, 복사된 객체의 깊이를 효과적으로 제한하지 못할 수 있습니다. 얕은 복사는 일부 객체만 수정하고, 다른 참조도 공유할 때 유용합니다. 하지만, 복사된 객체와 원본 객체가 동일한 참조를 공유하기 때문에, 예기치 못한 변경이 발생할 여지가 있습니다. 따라서, 개발자는 객체 복사의 목적과 해당 객체가 가진 속성에 대해 신중하게 판단하여 적합한 밸러스를 유지해주어야 합니다.