- 프로그래머스 문제를 풀던 중 변수에 값을 할당해 사용할려는데 값을 복사하는 것이 아니라 주소를 할당받아 버려서 동시에 수정 되어버리는 상황이 발생했다.
- 이를 위해 얕은 복사와 깊은 복사를 알기 위해 찾아 봤다.
기존 할당 방법
- 다른 언어와 다르게 파이썬은 할당 받는 변수의 이름 앞에 타입을 정하지 않는다.
- 이는 파이썬이 알아서 해주는 것인데, 이유는 값은 이미 할당되어 있어 변수의 이름으로 주소를 가르키는 것이다.
a = [1,2,3]
b = a
b[0] = 5
print(a)
print(b)
- 이와 같이 b의 값이 바뀌는 것이 아닌 a와 b가 동시에 바뀌는 것을 알 수있다.
- 값을 복사하는 것이 아니라 같은 곳을 바라보는 주소를 복사한것이기 때문이다. (C++과 비슷하다 볼수있다.)
깊은 복사 (Deep Copy) 방법
- 완전한 복사로 새로운 변수에 값을 넣어서 사용할 수 있게 해준다.
- 몇몇은 2중 배열이상 복사를 하지 못하는데, 이유는 아래와 같다.
- 파이썬은 변수를 할당 할때 기본적으로 주소를 가르킨다.
- 일반적인 복사에서는 해당 주소를 가르키지만, 2중 이상된 배열 같은경우 주소의 주소를 가르키기에 복사를 하더라도 주소이기 때문이다.
- C와 비슷하다고 보는데 주소를 변경하면 원래의 변수의 값까지 변경된다.
1. copy 모듈의 deepcopy() 이용하기
- 가장 많이 쓰이는 방법이라고 한다.
- 내장 모듈 copy를 import 하여 deepcopy() 함수를 사용한다.
- 2중 배열이상 완전한 복사가 가능하다.
import copy
a = [1, 2, 3, 4]
b = copy.deepcopy(a)
b[1] = 0
print(a, b)
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = copy.deepcopy()
b[4][2][0] = 0
print(a)
print(b)
2. 클래스가 가지고 있는 copy() 함수 이용하기
- 파이썬의 기본적인 클래스들이 가지고 있는 copy() 함수를 이용한다.
- list 클래스 역시 copy() 함수를 가지고 있다.
- 2중 배열이상 이상은 완전한 복사를 하지 못한다.
- 만약 같은 copy()를 사용해 완전한 복사를 할려면 deepcopy()를 사용해야 한다.
a = [1, 2, 3, 4]
b = a.copy()
b[1] = 0
print(a,b)
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = copy.deepcopy()
b[4][2][0] = 0
print(a)
print(b)
3. list를 생성할 때 매개변수에 원본을 전달, 혹은 생성후 원본리스트 확장
- list()와, extend()를 사용해서 만들수 있다.
- 2중 배열이상 이상은 완전한 복사를 하지 못한다.
a = [1, 2, 3, 4]
b = list(a)
b[1] = 0
print(a,b)
a = [1, 2, 3, 4]
b = []
b.extend(a)
b[1] = 0
print(a,b)
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = copy.deepcopy()
b[4][2][0] = 0
print(a)
print(b)
5. 리스트 슬라이싱
- 슬라이싱을 이용해 배열 완전 복사가 가능하다.
- 2중 배열이상 이상은 완전한 복사를 하지 못한다.
a = [1, 2, 3, 4]
b = a[:]
b[1] = 0
print(a,b)
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = a[:]
b[4][2][0] = 0
print(a)
print(b)
6. 배열 요소로의 접근을 통한 복사
- 매우 귀찮고 해야할것이 많은 작업이지만, 알고 있으면 좋을것 같다.
a = [1, 2, 3, 4]
b = [i for i in a]
b[1] = 0
print(a,b)
a = [1, 2, 3, 4]
b = []
for i in range(len(a)):
b.append(a[i])
b[1] = 0
print(a,b)
a = [1, 2, 3, 4]
b = []
for item in a:
b.append(item)
b[1] = 0
print(a,b)