다음과 같이 정의된 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 가 가능해진다.
':: python' 카테고리의 다른 글
python :: markdown to HTML 변환하기 (+테이블 테두리 설정) (0) | 2023.05.08 |
---|---|
python :: yaml 파일 읽기, yaml 데이터 json data로 변환하기 (0) | 2023.04.26 |
python :: 파이썬 1, 2, 3차원 배열(list) 선언 및 초기화(with java) (0) | 2022.08.23 |
python :: duckling, jpype 에러 해결 (TypeError: Parser must be a string or character stream, not java.lang.String) (0) | 2022.04.08 |
python :: 파이썬 테스트(unit test) 코드 작성 라이브러리 pytest 와 fixture (0) | 2022.02.03 |