파이썬 Python

[파이썬] 깊은 복사와 얕은 복사 개념, 예제

킹남지 2021. 6. 19. 03:41
반응형

파이썬의 깊은 복사와 얕은 복사의 개념을 알아보고 예제를 확인하겠습니다.

 

객체의 복사를 논하기 전에, 가변(mutable) 객체와 불변(immutable) 객체가 무엇인지 알아보겠습니다.

가변 객체, 불변 객체

  • 가변 객체 : 선언한 이후에도 값을 수정할 수 있는 객체. list, set, dictionary, 사용자가 작성한 대부분의 class가 해당됩니다.
  • 불변 객체 : 선언한 이후에 값을 수정할 수 없는 객체. 숫자형(int, float), bool, str, tuple 등이 해당됩니다.

일반적으로 불변 객체는 가변 객체보다 효율적입니다. 비교를 위한 조작의 단순화가 가능하고, 프로그램 내에 고정된 부분이 많아져 프로그램의 성능 개선에 도움이 된다고 합니다.

 

가변 객체인 리스트와 불변 객체인 튜플을 예로 차이를 확인해보겠습니다.

 

리스트 (list, mutable)

1
2
3
4
5
6
7
8
9
10
11
12
# list (mutable)
L1 = [123]
print(L1) 
print(id(L1)) 
# [1, 2, 3]
# 140501931789120
 
L1[0= 10
print(L1)
print(id(L1))
# [10, 2, 3]
# 140501931789120
cs

 

튜플 (tuple, immutable)

1
2
3
4
5
6
7
8
9
10
11
12
# tuple (immutable)
T1 = (123)
print(T1)
print(id(T1))
# (1, 2, 3)
# 140501931737648
 
T1 = (1023)
print(T1)
print(id(T1))
# (10, 2, 3)
# 140501932111424
cs

원소의 값을 변경할 때 리스트는 id값이 변경이 일어나지 않지만, 불변 객체인 tuple의 경우 원소의 값을 변경할 수 없으므로 새로운 tuple 인스턴스를 변수에 할당해, id값의 변경도 일어납니다. 변수가 가리키는 대상이 달라졌음을 알 수 있습니다.

 

깊은 복사, 얕은 복사

파이썬의 모든 변수는 객체 참조(reference)이므로 가변 객체를 복사할 때, b = a 라고 한다면 b는 실제 a가 가리키는(참조하는) 곳을 가리킨다는 점에 주의해야 합니다. 따라서 깊은 복사(deep copy)얕은 복사(shallow copy)를 알아보겠습니다.

얕은 복사(shallow copy)

얕은 복사의 경우, 위의 예시처럼 b 라는 새로운 객체를 생성하지만, 그 안에 들어가는 내용은 a와 같은 객체입니다. (참조하는 주소(id)가 같습니다.)

 

깊은 복사(deep copy)

깊은 복사의 경우, 복사를 위해 주소 값이 다른 새로운 객체를 생성하고, 내부의 객체들까지 모두 새롭게 생성됩니다.

 

예제를 보면서 어떤 차이인지 확인하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
= [123]
= a
 
b[0= 100 
 
print(a)
print(b)
# [100, 2, 3]
# [100, 2, 3]
 
print(id(a))
print(id(b))
# 140501999107280
# 140501999107280
cs

먼저, 얕은 복사입니다. b의첫 번째 원소의 값을 변경했는데, a의 첫 번째 원소 또한 변경됨을 확인할 수 있고 id값 또한 같습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
= [ [1,2], [34], [5,6] ]
= a[:]
 
print(id(a))
print(id(b))
# 140501931703584
# 140501931925248
 
print(id(a[0]))
print(id(b[0]))
# 140501931711056
# 140501931711056
cs

(주의) 리스트의 슬라이싱을 깊은 복사의 예제로 소개하는 책이 있는데 이 또한 얕은 복사에 해당할 수 있습니다. a의 원소가 immutable 객체인 경우는 해당 표현(리스트의 슬라이싱은 깊은 복사다.)에 문제가 없지만, mutable 객체라면 내부 객체의 id값이 같은 것을 확인할 수 있고, 해당 표현에 문제를 제기할 수 있습니다.

 

 

이제 깊은 복사의 예제를 보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import copy
 
= [0, [1,2], [34], [5,6] ]
= copy.deepcopy(a)
 
b[0= 10
b[1][0= 10
 
print(id(a))
print(id(b))
# 140501931703344
# 140501931826064
 
print(a)
print(b)
# [0, [1, 2], [3, 4], [5, 6]]
# [10, [10, 2], [3, 4], [5, 6]]
 
print(id(a[1]))
print(id(b[1]))
# 140501931825664
# 140501931839888
cs

깊은 복사입니다. copy모듈의 deepcopy() 메서드를 통해 내부의 객체들까지 모두 새롭게 생성됐음을 확인할 수 있습니다. 

 

얕은 복사와, 깊은 복사의 차이를 이해하는 데에 도움이 됐으면 좋겠습니다. 읽어주셔서 감사합니다^^

 

 

 

 

참고자료

[1] https://wikidocs.net/16038

 

 

반응형