본문 바로가기
파이썬/파이썬 기초

파이썬 깊은복사/얕은복사 알아보기

by Go! Jake 2021. 4. 26.

 

  파이썬에서 객체 복사하기

파이썬 복사에는 '깊은 복사'와 '얕은 복사'가 존재한다.

알고리즘 문제를 풀다보면 그래프, 리스트 등 여러 객체를 복사하여 원본을 그대로 두되 따로 수정본을 만들어야될 때가 있다. 파이썬에서는 '=' 연산자를 사용하여 복사하기도 하지만 이는 새로운 객체가 아닌 원본 객체의 reference만 공유하는 새로운 변수이다.

 

아래 내용에서 우린 원본 객체와 같은지 확인하기 위해 'id()'라는 함수를 통해 확인할 것이다. 파이썬의 모든 객체는 각자의 주소를 가지고 있다. 따라서 이 값이 같은지 틀린지 비교하여 같은 객체인지 다른 객체인지 판단할 수 있다.

 

Equal 연산자 사용하여 복사하기

input

new=[1,2,3,4,5]
old=new

new[1]=3

print("new",new,id(new))
print("old",old,id(new))

ouput

new [1, 3, 3, 4, 5] 138088629376
old [1, 3, 3, 4, 5] 138088629376

new[1]=3으로 변경되었는 데 new와 old 모두 변경된 것을 알 수 있고, 각각의 id도 동일하다는 것을 알 수 있다.

즉, 원본이 변경되면 이를 reference하는 변수도 같이 변경되는 것이다.

 

  Copy 모듈 사용하기

아래 copy 모듈을 import한다.

얕은 복사는 copy.copy()를 사용할 수 있다.

리스트의 경우 [:]를 뒤에 붙여 얕은 복사를 수행할 수 있다.

 

깊은 복사는 copy.deepcopy()를 사용하여 복사한다.

import copy

_list=[1,2,3]

_list_shallow_copy=copy.copy(_list)
_list_shallow_copy_2=_list[:]

_list_deep_copy=copy.deepcopy(_list)

 

  깊은 복사 (deep copy)

깊은 복사는 재귀적으로 복사하는 프로세스이다. 

새로운 collection (list, tuple,...) 객체를 생성하고 하위 객체를 덧붙인다. 즉 객체의 복사본이 다른 객체에 복사된다.

따라서 어떠한 변경도 원본 객체에 영향을 줄 수 없다.

copy.deepcopy()로 사용 가능하다.

 

input

import copy

_list=[1,2,[3,4]]

_list_deepcopy=copy.deepcopy(_list)

print("before deepcopy", _list,id(_list))
print("after deepcopy", _list_deepcopy,id(_list_deepcopy))


_list_deepcopy[2][0]=9 #deepcopy 값 변경하기

print("origianl after changes", _list,id(_list))
print("deepcopy after changes", _list_deepcopy,id(_list_deepcopy))

output

before deepcopy [1, 2, [3, 4]] 86317951424
after deepcopy [1, 2, [3, 4]] 86317949120
origianl after changes [1, 2, [3, 4]] 86317951424
deepcopy after changes [1, 2, [9, 4]] 86317949120

원본 리스트와 깊은 복사된 리스트는 다른 주소를 가지고 있다.

깊은 복사된 리스트에는 변경이 되었지만 원본 리스트에는 변경이 없는 것을 알 수 있다.

 

  얕은 복사 (shallow copy)

얕은 복사는 새로운 collection (list, tuple,...) 객체를 생성하고 하위 객체를 reference한다. 얕은 복사 프로세스는 재귀적이지 않고 따라서 하위 객체의 복사본을 생성하지 않는다. 따라서 reference한 객체에 변경이 생기면 원본 객체에도 변경이 생긴다.

input

import copy

_list=[1,2,[3,4]]

_list_shallowcopy=copy.copy(_list)

print("original", _list,id(_list))
print("shallowcopy", _list_shallowcopy,id(_list_shallowcopy))

print("child objects original", _list[2], id(_list[2]))
print("child objects shallowcopy", _list[2], id(_list_shallowcopy[2]))


_list_shallowcopy[2][0]=9 #deepcopy 값 변경하기

print("original after change", _list,id(_list))
print("shallowcopy after change", _list_shallowcopy,id(_list_shallowcopy))

print("child objects original after change", _list[2], id(_list[2]))
print("child objects shallowcopy after change", _list[2], id(_list_shallowcopy[2]))

output

original [1, 2, [3, 4]] 247893093376
shallowcopy [1, 2, [3, 4]] 247893091008

child objects original [3, 4] 247893090880
child objects shallowcopy [3, 4] 247893090880


original after change [1, 2, [9, 4]] 247893093376
shallowcopy after change [1, 2, [9, 4]] 247893091008

child objects original after change [9, 4] 247893090880
child objects shallowcopy after change [9, 4] 247893090880

전체 리스트를 비교하면 둘의 주소는 다르다. 하지만 하위 객체의 주소는 원본과 얕은 복사본 모두 동일하다는 점을 알 수 있으며, 하위 객체에서 변경이 생겼을 시에는 이러한 변경을 공유한다는 것을 알 수 있다.

 

  Reference

Geeksforgeeks www.geeksforgeeks.org/copy-python-deep-copy-shallow-copy/

 

댓글