Python 깊은 복사 - Python gip-eun bogsa

 파이썬에서 객체 복사하기

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

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

반응형

들어가기 앞서,

  • PS를 진행하다보면, 깊은 복사를 해야하는 경우가 있습니다.
  • Python에선, deepcopy 또는 slicing을 사용해 깊은 복사를 진행할 수 있습니다.
  • 해당 포스팅에선, slicing과 deepcopy를 사용한 깊은 복사 방법을 다뤄보겠습니다.
  • 속도는 slicing이 deepcopy보다 빠릅니다.

1차원 리스트의 깊은 복사

  • slicing 사용

      a = [1, 2, 3]
    
      b = a[:]
  • deepcopy 사용

      from copy import deepcopy
    
      a = [1, 2, 3]
    
      b = deepcopy(a)

2차원 리스트의 깊은 복사

  • slicing 사용

      a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
      b = [row[:] for row in a]
  • deepcopy 사용

      from copy import deepcopy
    
      a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
      b = deepcopy(a)

반응형

'Language > Python' 카테고리의 다른 글

[Python] Int를 Char로 변환 / Char를 Int로 변환  (0)2022.10.03
[Python] bisect란?  (0)2022.09.18
[Python] itertools란?  (0)2022.09.06
[Python] 우선순위큐(heapq) 사용법  (0)2022.07.02
[Python] Numpy 평균, 표준편차, 분산 계산  (0)2022.07.02