콘텐츠로 건너뛰기

Python 튜토리얼: 파이썬에서의 딥/셸로 복사 사용하기

[

Deep Copy와 Shallow Copy

Python에서 객체를 복사할 때, 대입문은 객체의 복사본을 생성하지 않으며, 객체에 이름을 바인딩(bind)한다. 이는 대부분의 경우(immutalbe 객체의 경우)에는 큰 차이를 만들지 않는다.

하지만 mutable 객체 또는 mutable 객체의 집합과 함께 작업할 때, 이러한 객체의 “진정한 복사본” 또는 “클론”을 생성하는 방법을 찾을 수도 있다. 이 기사에서는 Python 3에서 객체를 복사 또는 “클론”하는 방법을 자세히 설명한다.

유념할 점: 이 튜토리얼은 Python 3를 기준으로 작성되었지만, 객체 복사에 있어 Python 2와 3 사이에는 거의 차이가 없다. 차이가 있는 경우 본문에서 그 차이점을 언급할 것이다.

new_list = list(original_list)
new_dict = dict(original_dict)
new_set = set(original_set)

다만, 이 방법은 사용자 정의 객체에는 작동하지 않으며, 또한 얕은 복사(shallow copy) 만 생성한다는 것을 기억해야 한다. 리스트(list), 딕셔너리(dict), 셋(set)과 같은 복합 객체는 얕은(shallow) 복사와 깊은(deep) 복사 사이에 중요한 차이가 있다.

  • 얕은 복사는 새로운 컬렉션 객체를 생성한 다음, 그 원본에서 발견된 자식 객체에 대한 참조(reference)를 채워넣는다. 실제로 얕은 복사는 딱 한 단계까지만 깊게 복사한다. 이 복사 과정은 재귀(recursion)를 행하지 않기 때문에 자식 객체 자체의 복사본을 생성하지 않는다.

  • 깊은 복사는 복사 과정을 재귀적으로 수행한다. 즉, 먼저 새로운 컬렉션 객체를 생성한 다음, 원본에서 발견된 자식 객체의 복사본을 재귀적으로 채워넣는다. 이 방법으로 객체를 복사하면 원본 객체와 그 자식 객체들의 전체 객체 트리를 돌면서 원래 객체와 완전히 독립적인 복사본을 만드는 것이다.

이제 얕은 복사와 깊은 복사의 차이를 명확히 하기 위해 몇 가지 예제를 살펴보자.

얕은 복사 만들기

아래 예제에서는 새로운 중첩 리스트를 만들고, list() 팩토리 함수를 사용하여 얕은 복사를 한다.

xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ys = list(xs) # 얕은 복사

이렇게 하면 ysxs와 동일한 내용을 가진 새로운 독립적인 객체가 된다. 이를 확인하기 위해 두 객체를 조사해보자.

xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

실제로 xsys는 독립적인 객체임을 확인할 수 있다. 이를 확인하기 위해 작은 실험을 진행해보자. 원본(xs)에 새로운 서브리스트를 추가한 다음, 이 수정이 복사본(ys)에 영향을 주지 않는지 확인해본다.

xs.append(['new sublist'])
xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

예상한 대로 작동하는 것을 볼 수 있다. 얕은 복사로 원소 리스트의 “외부”수준을 수정하는 것은 전혀 문제가 없다.

하지만 얕은 복사만 수행한 것이기 때문에, ys는 여전히 원래 자식 객체를 참조하고 있음에 주의하자.