본문 바로가기
Python/Python 개념

얕은 복사와 깊은 복사

by hyun-am 2020. 9. 16.

얕은 복사와 깊은 복사 개요

 

파이썬의 할당문은 객체의 사본을 만들지 않으며 이름만 연결합니다. 변경할 수 없는 객체의 경우에는 일반적으로 차이가 없습니다.

하지만 만약 변경 가능한 객체 또는 변경 가능한 객체의 컬렉션(collection)을 다룰때면 이러한 객체의 '실체 사본' 또는 '복사본'을 만드는 방법이 필요할 수 있습니다.

이제 파이썬에서 객체를 복사하거나 '복제'하는 방법과 이때 주의할 사항을 몇가지 설명하겠습니다.

 

먼저 파이썬에 내장된 기본 컬렉션을 복사하는 방법을 보겠습니다. 내장된 기본 컬렉션은 list, set, dict가 있습니다. 이것들은 팩토리 함수에 건내 복사할 수 있습니다.

sample_list = list(original_list)
sample_dict = dict(original_list)
sample_set = set(original_list)

하지만 이런식으로 만드는 것(팩토리 함수)은 사용자 정의 객체는 처리하지 못하고 더 근본적으로 '얕은 복사본'을 만듭니다.

이제 여기서 '얕은 복사'와 '깊은 복사'는 중요한 차이가 있습니다.

 

얕은 복사

새 컬렉션 객체를 생성한 다음 원래 객체에서 찾은 자식 객체에 대한 참조로 채우는 것을 뜻합니다. 다시 말하자면 얕은 복사는 '한 단계 깊이'까지만 복사합니다.

 

먼저 얕은 복사본을 하나 만들겠습니다.

xs = [
    [0,1,0],
    [1,1,2],
    [1,1,9]
]
ys = list(xs)
print("xs :",xs)
print("ys :",ys)

# 출력 값
# xs : [[0, 1, 0], [1, 1, 2], [1, 1, 9]]
# ys : [[0, 1, 0], [1, 1, 2], [1, 1, 9]]

 

이제 ys는 xs와 똑같은 내용을 가지고 독립적인 객체가 되는것을 확인할 수 있습니다. 이제 ys가 정말로 xs로 부터 독립적인지 확인을 해보겠습니다.

 

먼저 xs에 값을 하나 추가해서 ys가 값이 변하는지 확인하겠습니다.

xs.append(["add_option"])
print("xs :",xs)
print("ys :",ys)

# 출력 값
# xs : [[0, 1, 0], [1, 1, 2], [1, 1, 9], ['add_option']]
# ys : [[0, 1, 0], [1, 1, 2], [1, 1, 9]]

 

xs에만 값을 추가 했으니 당연히 xs에만 추가된 것을 확인할 수 있습니다. 이것은 '얕은' 수준에서 복사된 리스트를 수정하는 것은 문제되어 보이지 않습니다. 이제 ys가 xs에 원래 참조했던 항목중에 하나를 수정한 후 확인해 보겠습니다.

xs[0][2] = "수정"
print("xs :",xs)
print("ys :",ys)
# 출력 값
# xs : [[0, 1, '수정'], [1, 1, 2], [1, 1, 9]]
# ys : [[0, 1, '수정'], [1, 1, 2], [1, 1, 9]]

 

이렇게 xs의[0][2]번째 값만 수정했는데 ys의 값도 같이 바뀐것을 확인할 수 있습니다. 이것은 ys가 xs를 참조했기 때문에 '얕은 복사'이기 때문에 완전히 독립적이지 않습니다.

 

 

깊은 복사

복사 프로세스를 재귀적으로 처리합니다. 우선 새 컬렉션 객체를 생성한 다음 원래 객체에서 찾은 자식 객체의 복사본을 재귀적으로 채우는것을 뜻합니다. 또한 이 방법으로 복사하면 원래 객체의 전체 객체 트리를 따라 그 자식들까지 완전히 독립적으로 복사된 복제본을 만들 수 있습니다.

 

여기서 깊은 복사를 위해 copy에서 deepcopy를 이용하겠습니다.

import copy

test_data = [
    ['가','나','다'],
    ['라','마','바'],
    ['사','아','자']
]

deep_copy_data = copy.deepcopy(test_data)

print("test_data : ", test_data)
print("deep_copy_data : ", deep_copy_data)
# 출력 값
# test_data :  [['가', '나', '다'], ['라', '마', '바'], ['사', '아', '자']]
# deep_copy_data :  [['가', '나', '다'], ['라', '마', '바'], ['사', '아', '자']]

 

이제 test_data에서[0][0]항목을 변경시키겠습니다.

 

test_data[0][0] = "수정"
print("test_data : ", test_data)
print("deep_copy_data : ", deep_copy_data)
# 출력 값
# test_data : [['수정', '나', '다'], ['라', '마', '바'], ['사', '아', '자']]
# deep_copy_data : [['가', '나', '다'], ['라', '마', '바'], ['사', '아', '자']]

test_data 값만 바뀌어서 복사한 객체와 원래 객체가 완전히 분리되어 독립적으로 된 것을 확인할 수 있습니다.

 

'Python > Python 개념' 카테고리의 다른 글

파이썬 자료구조(심화)-2  (0) 2020.09.17
파이썬 자료구조(심화)-1  (0) 2020.09.16
*args와 **kwargs  (0) 2020.09.14
파이썬 - 데코레이터  (0) 2020.09.14
파이썬 문자열 다루기  (1) 2020.05.25

댓글