Python 기초 | 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)

원준·2023년 4월 21일

파이썬

목록 보기
16/21
  • 프로그래머스 문제를 풀던 중 변수에 값을 할당해 사용할려는데 값을 복사하는 것이 아니라 주소를 할당받아 버려서 동시에 수정 되어버리는 상황이 발생했다.
  • 이를 위해 얕은 복사와 깊은 복사를 알기 위해 찾아 봤다.

기존 할당 방법

  • 다른 언어와 다르게 파이썬은 할당 받는 변수의 이름 앞에 타입을 정하지 않는다.
  • 이는 파이썬이 알아서 해주는 것인데, 이유는 값은 이미 할당되어 있어 변수의 이름으로 주소를 가르키는 것이다.
# 예시
a = [1,2,3]
b = a
b[0] = 5
print(a) #[5, 2, 3]
print(b) #[5, 2, 3]
  • 이와 같이 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) # [1, 2, 3, 4] [1, 0, 3, 4]
######## 2중이상 배열 테스트 ##############
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = copy.deepcopy()
b[4][2][0] = 0
print(a) # [1, 2, 3, 4, [5, 6, [7, 8, [9, 10]]]]
print(b) # [1, 2, 3, 4, [5, 6, [0, 8, [9, 10]]]]

2. 클래스가 가지고 있는 copy() 함수 이용하기

  • 파이썬의 기본적인 클래스들이 가지고 있는 copy() 함수를 이용한다.
  • list 클래스 역시 copy() 함수를 가지고 있다.
  • 2중 배열이상 이상은 완전한 복사를 하지 못한다.
    • 만약 같은 copy()를 사용해 완전한 복사를 할려면 deepcopy()를 사용해야 한다.
a = [1, 2, 3, 4]
b = a.copy()
b[1] = 0
print(a,b) # [1, 2, 3, 4] [1, 0, 3, 4]
######## 2중이상 배열 테스트 ##############
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = copy.deepcopy()
b[4][2][0] = 0
print(a) # [1, 2, 3, 4, [5, 6, [0, 8, [9, 10]]]]
print(b) # [1, 2, 3, 4, [5, 6, [0, 8, [9, 10]]]]

3. list를 생성할 때 매개변수에 원본을 전달, 혹은 생성후 원본리스트 확장

  • list()와, extend()를 사용해서 만들수 있다.
  • 2중 배열이상 이상은 완전한 복사를 하지 못한다.
# 1번째 방법
a = [1, 2, 3, 4]
b = list(a)
b[1] = 0
print(a,b) # [1, 2, 3, 4] [1, 0, 3, 4]
# 2번째 방법
a = [1, 2, 3, 4]
b = []
b.extend(a)
b[1] = 0
print(a,b) # [1, 2, 3, 4] [1, 0, 3, 4]
######## 2중이상 배열 테스트 ##############
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = copy.deepcopy()
b[4][2][0] = 0
print(a) # [1, 2, 3, 4, [5, 6, [0, 8, [9, 10]]]]
print(b) # [1, 2, 3, 4, [5, 6, [0, 8, [9, 10]]]]

5. 리스트 슬라이싱

  • 슬라이싱을 이용해 배열 완전 복사가 가능하다.
  • 2중 배열이상 이상은 완전한 복사를 하지 못한다.
a = [1, 2, 3, 4]
b = a[:]
b[1] = 0
print(a,b) # [1, 2, 3, 4] [1, 0, 3, 4]
######## 2중이상 배열 테스트 ##############
a = [1, 2, 3, 4, [5,6, [7,8,[9,10]]]]
b = a[:]
b[4][2][0] = 0
print(a) # [1, 2, 3, 4, [5, 6, [0, 8, [9, 10]]]]
print(b) # [1, 2, 3, 4, [5, 6, [0, 8, [9, 10]]]]

6. 배열 요소로의 접근을 통한 복사

  • 매우 귀찮고 해야할것이 많은 작업이지만, 알고 있으면 좋을것 같다.
# 1번째 방법
a = [1, 2, 3, 4]
b = [i for i in a]
b[1] = 0
print(a,b) # [1, 2, 3, 4] [1, 0, 3, 4]
# 2번째 방법
a = [1, 2, 3, 4]
b = []
for i in range(len(a)):
    b.append(a[i])
b[1] = 0
print(a,b) # [1, 2, 3, 4] [1, 0, 3, 4]
# 3번째 방법
a = [1, 2, 3, 4]
b = []
for item in a:
    b.append(item)
b[1] = 0
print(a,b) # [1, 2, 3, 4] [1, 0, 3, 4]
profile
공부해보자

0개의 댓글