Shallow Copy와 Deep Copy
Python에서 assignment를 수행될 때,
- 오른쪽이 reference (즉 variable이 =연산자 우측에 있음)인 경우
- 기본적으로 Shallow Copy가 발생한다.
하지만 특정 경우에는 Deep Copy 가 필요한 경우가 있기 때문에 이 둘의 차이를 명확히 알고 있는 것이 중요하다.
이 둘의 차이는 다음 그림이 간략하게 설명해 준다.

Shallow copy가 일어났다면
- 왼쪽의 경우처럼 실제 데이터가 있는 메모리영역 Referenced Object가 공유되고
- 이를 참조하는 새로운 Cloned Object가 만들어진다.
때문에 실제로는 같은 Object를 가리키고 있기 때문에
- Original Object에서 수정이 일어나면
- 해당 수정사항이 Cloned Object를 통해 접근하는 경우에도 똑같이 반영이 된다.
Deep copy는
- copy가 일어나는 시점에 똑같은 값을 가지는 Object를 새로 생성하고
- 해당 새로 생성된 Object를 가리키게 한다.
때문에 이후로는 각각의 reference가 다른 memory 영역을 가리키므로 한쪽의 수정이 다른 쪽에는 반영이 되지 않는다.
일반적으로 매우 큰 메모리를 차지하고 있는 object나
dynamic programming 등에서 사용되는 object 들은 shallow copy가 유용하지만,
값만 똑같고 다른 메모리 영역에 새로 할당을 꼭 해야 하는 경우나
원본은 보존하고 원본에 대한 복사본에서 처리를 하는 경우 등에는
deep copy가 꼭 필요하다.
단순 Assignment : 같은 object를 가리킴
Python에서 assignment는
- 왼쪽 variable (or name, reference)이 오른쪽에 놓인 value(or Object)를 참조하도록 하는 것으로
- 오른쪽 expression의 최종값을 value로 가지는 Object를 왼쪽의 variable이 가리키도록(refer to) 할당(=해당 object를 참조).
2023.06.13 - [Programming] - [Python] Variable (and Object)
[Python] Variable (and Object)
Python에서 Variable은 Memory에 할당된 Ojbect를 참조하는 Name (=Reference)에 불과하다. 이 문서에서 Object는 Python에서의 Object로 type과 value, ID (CPython에서는 할당된 memory address), 그리고 reference count를 가지
dsaint31.tistory.com
즉, variable(or reference)이 assignment에서 오른쪽 operand인 경우,
왼쪽 operand인 variable(or reference)도 같은 object를 참조하게 된다.
immutable object에 대한 variable 이 우측 operand인 경우.
다음 예제 코드는 오른쪽 operand인 variaible이 immutable
object를 참조하는 경우이며 d0
와 d1
가 가리키는 object들이 같은 ID를 가지게 됨(=같은 Object 참조)
# 단순 assignment.는 shallow copy! d0 = (1,2,3) d1 = d0 print(f'id of d0:{id(d0)}, id of d1:{id(d1)}')
결과는 다음과 같음.
id of d0:140488388961920, id of d1:140488388961920 d1 is d0 : True d1 == d0 : True
tuple은 immutable.
주의할 것은 immutable
object의 copy constructor
를 assignment의 오른쪽 operand로 놓은 경우도 같은 object를 가리키게 된다는 점이다. (생성을 하는 것처럼 보이지만... 변경불가의 object를 굳이 다시 만들 필요가 없으므로)
d2 = tuple(d0) print(f'id of d2:{id(d2)}') print(f'd1 is d0 : {d1 is d0}') print(f'd1 == d0 : {d1 == d0}')
결과는 다음과 같음.
id of d2:140488388961920 d1 is d0 : True d1 == d0 : True
mutable object에 대한 variable 이 우측 operand인 경우.
Mutable
의 경우도 단순 assignment는 같은 memory 영역을 가리킴 (Variable은 단순 reference임을 잊지 말자).
# Muutable obj.는 shallow copy! d0 = [1,2,3] d1 = d0 print(f'id of d0:{id(d0)}, id of d1:{id(d1)}') print(f'd1 is d0 : {d1 is d0}') print(f'd1 == d0 : {d1 == d0}')
결과는 다음과 같음.
id of d0:140489189478208, id of d1:140489189478208 d1 is d0 : True d1 == d0 : True
단, immutable
의 경우와 달리 mutable
object에 대한 variable을 이용한 copy constructor에서는 새로 memory할당이 된 object를 가리키게 된다.
d2 = list(d0) print(f'id of d2:{id(d2)}') print(f'd1 is d0 : {d2 is d0}') print(f'd1 == d0 : {d2 == d0}')
결과
id of d2:140650393264576 d1 is d0 : False d1 == d0 : True
[:]를 이용한 경우
immutable
의 경우엔 단순히 assignment 한 것과 같은 결과 이지만, mutable
인 경우엔 다른 메모리 영역에 새로 할당 이 이루어진다.
주의할 것은 deep copy는 아니라는 점임.
immutable의 경우
d0 = ([1,2,3],1,2,3) #Immutable d1 = d0[:] print(f'id of d0:{id(d0)}, id of d1:{id(d1)}') print(f'd1 is d0 : {d1 is d0}') print(f'd1 == d0 : {d1 == d0}')
결과
id of d0:140488387426592, id of d1:140488387426592 d1 is d0 : True d1 == d0 : True
mutable의 경우
d0 = [[1,2,3],1,2,3] # mutable d1 = d0[:] print(f'id of d0:{id(d0)}, id of d1:{id(d1)}') print(f'd1 is d0 : {d1 is d0}') print(f'd1 == d0 : {d1 == d0}')
결과
id of d0:140488387495104, id of d1:140488387053504 d1 is d0 : False d1 == d0 : True
주의할 것은 item이 list
와 같은 mutable collection인 경우 item 들이 새로 만들어지는 것은 아니라는 점이다.
d0 = [[1,2,3],1,2,3] d1 = d0[:] d1[0][0] = 777 print(f'd0:{d0}\nd1:{d1}')
결과
d0:[[777, 2, 3], 1, 2, 3] d1:[[777, 2, 3], 1, 2, 3]
앞서 본 것처럼 d0
와 d1
은 다른 메모리 영역(list
를 위해 할당된)을 가리키나,
해당 list
의 index 0인 item이 mutable
인 [1,2,3]
list이며 이는 d0
와 d1
이 공유하고 있다.
때문에 한쪽을 수정할 경우 다른 쪽에도 영향을 주어 777
로 바뀐 것을 볼 수 있음.
즉, shallow copy가 이루어진 것임.
만약 item이 immutable collection이라면?
immutable collection은 수정이 안되기 때문에 변경이 이루어지면 그냥 새로 생성하여 할당이 된다. 때문에 shallow copy이지만 마치 deep copy처럼 변경된 것으로 보일 수 있으나, 해당 item에 처리가 이루어질 때 아예 다른 object가 만들어져서 재할당된 것이지 앞서의 assignment에서 deep copy가 된 건 아님.
d0 = [(1,2,3),1,2,3] d1 = d0[:] # 이 시점까지 shallow copy로 ,d0와 d1모두 같은 (1,2,3) object를 가르킴. print (d0[0] is d1[0]) d1[0] += (4,5) # tuple에 대한 augmented assignment는 새로운 object를 생성하고 재할당임. print (d0[0] is d1[0]) print(f'd0:{d0}\nd1:{d1}')
결과는 다음과 같음.
True False d0:[(1, 2, 3), 1, 2, 3] d1:[(1, 2, 3, 4, 5), 1, 2, 3]
copy 메서드를 이용한 경우 (=shallow copy)
immutable object들에서는 copy
메소드가 지원되지 않으며, mutable object에서만 지원함.
기본적으로 새로운 메모리 영역을 할당하지만, item으로 있는 mutable
object들은 공유를 하기 때문에 shallow copy임.

위의 그림에서 왼쪽에 해당하며,bag0
에 대해 shallow copy를 수행한 bag1
경우처럼 item들은 새로 만들어지는 것이 아니다.
a = [[1,2,3],'test'] b = a.copy() print(f'a is b:{a is b}') b[0][0]=77 print(f'a is {a}\nb is {b}')
결과는 다음과 같음
a is b:False a is [[77, 2, 3], 'test'] b is [[77, 2, 3], 'test']
deep copy : copy 모듈의 deepcopy() 함수
mutable
object가 item인 collection 객체들에 대해 deep copy를 하기 위해선 copy
모듈의 deepcopy
함수를 사용한다.
다음 예제 코드를 참고하라.
import copy a = [[1,2,3],'test'] c = copy.deepcopy(a) c[0][0] = 77 print(f'a is {a}\nb is {c}')
결과는 다음과 같다
a is [[1, 2, 3], 'test'] b is [[77, 2, 3], 'test']
literal의 경우
Python의 경우 memory의 효율적 사용을 위해서
literal 및 constant 등에 대해선 copy constructor
와 같이 동일한 memory 영역을 가리키는 형태로 처리함.
literal이란 : https://dsaint31.tistory.com/entry/Basic-Literal
[Basic] Literal
소스 코드 상에서 고정된 값을 가르킴. (또는 고정된 값을 나타내는 표기법을 의미함.) literal 은 문자 그대로 라는 뜻을 가짐. C와 같이 primitive datatype의 변수에 할당되는 값들을 주로 의미하나, Py
dsaint31.tistory.com
다음 예제 코드를 참고하라.
a = 7 b = 7 print(f'a is b: {a is b}') c = b print(f'c is a: {c is a}')
결과는 다음과 같음.
a is b: True c is a: True
memory의 효율적 사용을 위해서 literal
및 copy constructor
에선 shallow copy와 같이 같은 memory의 영역을 가리키게 됨.
물론 명시적으로 다음과 같이 값만 같은 tuple
을 따로 할당 하면 다른 memory 영역에 생성 됨
(이 부분이 literal
과 다름)
a = (1,2) b = (1,2) print( f'a is b :{a is b} / a == b : {a ==b}')
결과
a is b :False / a == b : True
'Programming' 카테고리의 다른 글
[Python] Iterable and Iterator, plus Generator (1) | 2023.06.07 |
---|---|
[Python] List Comprehension (0) | 2023.06.06 |
[Programming] Garbage Collection (GC) (0) | 2023.06.05 |
[Python] Interpreter and PVM (Python Virtual Machine) (1) | 2023.06.05 |
[Python] recursive call : Fibonacci Sequence (0) | 2023.05.24 |