본문 바로가기
개발상식

[개발상식] 참조복사, 얕은복사, 깊은복사(얕은복사와 참조복사는 같은말일까?)

by devjh 2020. 9. 22.
반응형

이번게시글에서는 참조복사, 얕은복사, 깊은복사에 대해 포스팅 하겠습니다.

 

세가지 키워드들은 프로그래밍 언어별로 조금은 다르게 해석합니다.

 

(객체에 메모리 주소를 공유하는걸 얕은복사라고하는사람도 있고 참조복사라고 하는사람도 있습니다.)

 

이유도 나름대로 정리해보겠습니다.

 

언어는 python을 사용하여 예제를 만들어봤습니다.

 

1. 참조복사

a = [1,2,3]
b = a

b[0] = 4

print(a) // [4, 2, 3] 출력
print(b) // [4, 2, 3] 출력

 

리스트 a를 선언 내부에는 1,2,3을 넣어주었습니다.

 

b에 a를 복사하고 b의 첫번째값을 4로 변경한 예제입니다.

 

mutable한 특징을 가지고있는 객체들은 

 

단순히 b = a로 복사할경우 참조해야할 주소의 값이 복사되어

 

주소를 공유하게되고 한쪽을 변경할경우 다른쪽에도 영향이 가게됩니다.

 

2. 얕은복사

a = [1,2,3]
b = a.copy()

print(id(a)) // 30921832 출력
print(id(b)) // 32002856 출력

b[0] = 4

print(a) // [1, 2, 3] 출력
print(b) // [4, 2, 3] 출력

 

얕은복사란 new같은 키워드를 사용해 메모리를 새로 할당해주고 for문을 돌려 내부의 요소를 직접 넣어주는 복사를 칭합니다.

 

파이썬에서는 copy()라는 메서드를 통해 얕은복사가 가능합니다.

 

메모리가 새로 할당되었기에 주소값이 다르며 한쪽을 변경하여도 다른쪽에 영향이 가지 않습니다.

 

3. 깊은복사

a = [[1,2],3]
b = a.copy()

b[0][0] = 4

print(id(a)) // 29381416 출력
print(id(b)) // 29382248 출력

print(a) // [[4, 2], 3] 출력
print(b) // [[4, 2], 3] 출력

print(id(a[0])) // 16340936 출력
print(id(b[0])) // 16340936 출력

 

객체의 value로 또 mutable한 객체가 들어가있을때가 문제입니다.

 

얕은복사와 참조복사의 개념을 혼동시킨 장본인입니다.

 

a와 b는 주소가 다릅니다.

 

그러나 a[0]과 b[0]의 주소는 같습니다.

 

그래서 주소가 다른 객체에 접근해 내부요소를 바꿔 줬지만 이전의 데이터에 영향이 간 것입니다.

 

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

b[0][0] = 4

print(a) // [[1,2],3] 출력
print(b) // [[4,2],3] 출력

 

파이썬의 copy모듈을 import하여 deepcopy를 사용하면 객체 내부의 객체까지

 

모두 메모리를 새로 할당하여 복사할 수 있습니다.

 

4. 왜 해당용어는 사람들마다 다르게 쓰일까?

 

참조복사 얕은복사 깊은복사에 대해 알아보았습니다.

 

그러나 

 

c++개발자, c# 개발자 java개발자들은 보통 주소값을 공유하는 복사를 얕은복사

 

new 키워드를 사용해 메모리 할당, 내부에 직접 접근해 값을 복사해주는 복사를 깊은복사라고 합니다.

 

제가 생각하는 이유입니다.

 

a = [[1,2],3]
a = [[1,2],[3]]

c# java등의 언어에서 이러한 배열 및 객체를 복사할때는

 

new로 메모리들을 생성해주고 원시타입의 데이터가 나올때까지 for문을 돌려서 복사해 주게 됩니다.

 

새로운 메모리를 할당해주고 내부에 원시타입이 나올때까지 접근하는 로직은 동일한데

 

내부에 배열이 하나 더있다고 용어를 굳이 차별화 하지 않게 된게 아닐까..?

 

라고 생각합니다.

 

그러나 파이썬은 copy모듈에 아에 deepcopy가 있으므로 깊은복사라는 용어로 굳혀진게 아닐까 싶습니다.

반응형

댓글