:: python

python :: 파이썬 딕셔너리 복사(copy) 후 수정사항 반영되지 않도록 하기(deepcopy)

토람이 2022. 11. 21. 19:13

다음과 같이 정의된 A 딕셔너리를 복사하여 B 딕셔너리를 만들었다.

A = {'name': 'toram', 'lotto': [1, 2, 3, 4, 5, 6]}
B = {k:v for k, v in A.items()}

 

이 때, 새로 생성한 B['lotto'] 의 내용을 수정했더니 기존 딕셔너리(A)에도 동일하게 반영되었다.

B['lotto'][2] = 20

print(B['lotto'])
# [1, 2, 20, 4, 5, 6]

print(A['lotto'])
# [1, 2, 20, 4, 5, 6]

 

아예 새로 정의하여 별개의 딕셔너리라고 생각했는데,

수정사항이 반영된 걸 보니 당황했다 @.@

 

구글링을 통해 여러 가지 방법을 시도해봤지만 모두 실패했다.

# 1차시도
B = A

# 2차시도
B = A.copy()

# 3차시도
B = dict(A)

# 4차시도
B = dict({k:v for k, v in A.items()})

 

 

0. Shallow Copy 와 Deep Copy

객체 복사(copy) 의 방법은 크게 shallow copy, deep copy 로 나눌 수 있다.

shallow copy 는 말 그대로 대상을 얕게(shallow) 복사하는 것으로,

객체의 데이터 값을 완전히 복사하는 것이 아니라 객체의 주소값만 복사한다.

 

위에서 시도했던 모든 방법들은 shallow copy 라고 볼 수 있다.

B는 A의 주소값을 복사했기 때문에

B 의 내용이 변경될 경우

같은 메모리 공간 주소를 바라보고 있는 A 도 동일하게 변경된 내용이 반영되는 것이다.

 

이런 일을 방지하기 위해서는 deep copy 가 필요하다.

deep copy 객체의 데이터 값을 새로운 메모리 공간에 복사하는 것으로,

A와 B가 별개의 객체로 동작할 수 있게 된다.

즉, A의 변경사항이 B에는 반영되지 않게 된다.

 

 

1. copy 라이브러리로 deepcopy

deep copy 를 할 때, 'copy' 라이브러리를 사용하는 방법이 많이 쓰이는 듯했다.

import copy

B = copy.deepcopy(A)

 

위와 같이 copy 라이브러리의 deepcopy 함수를 사용하면 deep copy 가 이루어져

변경사항이 서로 반영되지 않는다.

 

2. 라이브러리 없이 deep copy 하기

1번의 copy 라이브러리를 활용하는 방법이 보다 쉬워 보이지만,

알고리즘 문제를 풀던 나는 import 구문 없이 deep copy 를 해야했다.

 

열심히 구글링한 결과

B = {key: value[:] for key, value in A.items()}

 

이렇게 하니 된다.

ㅋ;

 

뭔가 허무하다 싶어서 A와 B를 다음과 같이 선언하여 테스트해보니

동일한 문제가 발생하지 않는다.

A = {'name': 'toram', 'age': 1}
B = {k:v for k, v in A.items()}


# A 딕셔너리 내용 수정
B['age'] = 2

print(B['age'])
# 2

print(A['age'])
# 1

 

위와 같이 선언한 경우에는 deep copy 가 이루어진 것이다.

차이를 알겠는가^.^?

 

 

복사하려 했던 A 딕셔너리의 value 가 단일값이라면

{k:v for k, v in A.items()}

의 구문으로도 deep copy 가 이루어진다.

 

그러나, A 딕셔너리의 value 값이 list 인 경우는 위 구문으로 shallow copy 가 이루어진다.

list 의 element 모두를 복사하겠다고 명시적으로 표현해주어야 (v[:])

완전히 새로운 딕셔너리로 deep copy 가 가능해진다.

 

300x250