새소식

반응형
Programming Language/Python

[Python] 파이썬 얕은 복사, 깊은 복사(copy, deepcopy)

  • -
반응형

 

1. 파이썬 얕은 복사(Shallow Copy)


파이썬에서 얕은 복사(Shallow Copy)는 데이터 구조의 최상위 요소(일반적으로 리스트, 딕셔너리 또는 다른 컬렉션)만 복사되고 내부 요소는 원본과 동일한 참조를 유지하는 복사 작업을 의미한다. 이는 데이터 구조의 최상위 레벨에서만 복사가 이루어지기 때문에 내부 요소가 변경되면 복사본과 원본 모두에 영향을 미친다.

 

예제 코드 - 리스트 슬라이싱 를 이용한 얕은 복사

original_list = [1, 2, [3, 4]]
shallow_copy = original_list[:]

# 원본 리스트와 얕은 복사 리스트 출력
print("Original List:", original_list)
print("Shallow Copy:", shallow_copy)

# 원본 리스트에 요소 추가
original_list.append(5)

# 얕은 복사 리스트에 요소 추가
shallow_copy[2].append(6)

# 변경 후 리스트 출력
print("Original List (after appending 5):", original_list)
print("Shallow Copy (after appending 6 to the inner list):", shallow_copy)
Original List: [1, 2, [3, 4]]
Shallow Copy: [1, 2, [3, 4]]
Original List (after appending 5): [1, 2, [3, 4, 6], 5]
Shallow Copy (after appending 6 to the inner list): [1, 2, [3, 4, 6]]
  1. 원본 리스트 original_list는 3개의 요소로 구성되며, 세 번째 요소는 내부 리스트 [3,4]를 포함한다.
  2. 얕은 복사는 슬라이싱(original_list [:])을 통해 이루어진다. 이로 인해 최상위 요소(1,2, [3,4])가 복사된다.
  3. 원본 리스트에 요소를 추가하면 원본 리스트 자체가 변경된다.
  4. 얕은 복사 리스트에는 변경이 전파되지 않는다. 그러나 얕은 복사의 내부 리스트 [3,4]는 원본 리스트의 내부 리스트와 동일한 참조를 가지므로 내부 리스트를 변경하면 얕은 복사본도 동일한 변경이 반영된다.

따라서 얕은 복사는 복합 객체의 요소가 변경 가능한 객체(리스트, 딕셔너리)인 경우, 그 객체들을 공유하게 된다. 만약 완전한 독립적인 복사본을 생성하고 싶다면, 깊은 복사(deepcopy)를 사용해야 한다. 깊은 복사는 모든 객체와 내부 객체를 재귀적으로 복사하여 완전히 독립적인 복사본을 생성한다.

 

예제 코드 - 딕셔너리를 이용한 얕은 복사

import copy

original_dict = {'a': 1, 'b': [2, 3]}
shallow_copy = copy.copy(original_dict)

# 원본 딕셔너리와 얕은 복사 딕셔너리 출력
print("Original Dictionary:", original_dict)
print("Shallow Copy:", shallow_copy)

# 원본 딕셔너리와 얕은 복사 딕셔너리에 요소 추가
original_dict['c'] = 4
shallow_copy['b'].append(5)

# 변경 후 딕셔너리 출력
print("Original Dictionary (after adding 'c'): ", original_dict)
print("Shallow Copy (after appending 5 to 'b' key):", shallow_copy)
Original Dictionary: {'a': 1, 'b': [2, 3]}
Shallow Copy: {'a': 1, 'b': [2, 3]}
Original Dictionary (after adding 'c'):  {'a': 1, 'b': [2, 3, 5], 'c': 4}
Shallow Copy (after appending 5 to 'b' key): {'a': 1, 'b': [2, 3, 5]}
  1. original_dict는 초기에 {'a' : 1, 'b' : [2,3]}와 같은 딕셔너리를 가지고 있다.
  2. shallow_copy는 copy.copy()를 사용하여 original_dict를 얕은 복사 하여 생성되었다. 따라서 original_dict와 shallow_copy는 다른 객체를 참조하게 된다.
  3. 원본 딕셔너리와 얕은 복사 딕셔너리를 출력한 후, 원본 딕셔너리에 'c' 키를 추가하고 얕은 복사본의 'b' 키의 리스트에 5를 추가했다.

결과적으로 original_dict에 'c'를 추가한 경우  얕은 복사본 shallow_copy에는 영향을 주지 않는다. 그러나 original_dict의 'b'키의 리스트에 5를 추가한 경우 shallow_copy의 'b'키의 리스트도 같은 리스트를 참조하고 있으므로 shallow_copy의 'b'키의 리스트에도 5가 추가되었다.

 

정리를 하자면 얕은 복사는 원본 객체와 복사본 객체가 다른 객체로 존재하고 있지만, 원본 객체와 복사본 객체는 동일한 객체를 참조하는 경우에 영향을 받을 수 있다. 일반적으로 얕은 복사는 복합 객체(리스트, 딕셔너리 등)에 대해 발생하며, 이러한 복합 객체의 요소를 변경할 때 원본과 복사본이 동일한 객체를 참조하게 된다.

 

따라서 얕은 복사를 수행한 경우에는 다음과 같이 요약할 수 있다.

 

  1. 원본 객체를 변경하면 복사본 객체에 영향을 미친다.
  2. 복사본 객체에서 iterable(반복 가능한) 요소(예 : 리스트 또는 딕셔너리의 값)를 변경할 때도 원본 객체에 영향을 미친다.

다시 한번 강조하면, 얕은 복사는 복합 객체의 내부 요소가 변경 가능한 객체일 때 주로 발생하며, 이러한 객체들은 동일한 참조를 공유하게 된다. 

 

 

2. 파이썬 깊은 복사(Deep Copy)


파이썬에서 깊은 복사(Deep Copy)는 데이터 구조의 모든 요소, 포함된 모든 객체와 내부 객체를 새로운 복사본으로 복제하는 방법을 말한다. 즉, 깊은 복사는 원본 객체와 복사본 간의 모든 객체 참조를 분리한다. 이로 인해 원본 객체의 변경이 복사본에 영향을 미치지 않는다. 

 

깊은 복사를 수행하기 위해서는 copy 모듈의 deepcopy() 함수를 사용하거나 다른 라이브러리나 메서드를 활용할 수 있다. 

 

예제 코드 1

import copy

# 원본 리스트
original_list = [1, 2, [3, 4]]

# 깊은 복사 수행
deep_copy = copy.deepcopy(original_list)

# 원본 리스트에 요소 추가
original_list.append(5)

# 깊은 복사 리스트에 요소 추가
deep_copy[2].append(6)

# 변경 후 리스트 출력
print("Original List (after appending 5):", original_list)
print("Deep Copy (after appending 6 to the inner list):", deep_copy)
Original List (after appending 5): [1, 2, [3, 4], 5]
Deep Copy (after appending 6 to the inner list): [1, 2, [3, 4, 6]]

위의 예제처럼 깊은 복사를 사용하면 원본 객체와 복사본 객체가 완전히 독립적인 객체가 되며, 원본 객체의 변경이 복사본 객체에 영향을 주지 않는다. 

 

  1. original_list는 [1,2, [3,4]]와 같은 리스트로 초기화되었다.
  2. deep_copy는 copy.deepcopy()를 사용하여 original_list를 깊은 복사 하여 생성되었다. 따라서 original_list와 deep_copy는 서로 다른 객체를 참조하게 된다.
  3. 원본 리스트와 깊은 복사 리스트를 출력한 후, 원본 리스트에 5를 추가하고 깊은 복사 리스트의 내부 리스트에 6을 추가했다.

결과적으로 원본 리스트에 5를 추가한 경우 깊은 복사 리스트에는 영향을 주지 않았으며, 깊은 복사 리스트의 내부 리스트에 6을 추가한 경우 원본 리스트에도 영향을 주지 않았다. 

 

 

예제 코드 2

import copy

original_dict = {'a': 1, 'b': [2, 3]}
deep_copy = copy.deepcopy(original_dict)

# 원본 딕셔너리와 깊은 복사 딕셔너리 출력
print("Original Dictionary:", original_dict)
print("Deep Copy:", deep_copy)

# 원본 딕셔너리와 깊은 복사 딕셔너리에 요소 추가
original_dict['c'] = 4
deep_copy['b'].append(5)

# 변경 후 딕셔너리 출력
print("Original Dictionary (after adding 'c'): ", original_dict)
print("Deep Copy (after appending 5 to 'b' key):", deep_copy)
Original Dictionary: {'a': 1, 'b': [2, 3]}
Deep Copy: {'a': 1, 'b': [2, 3]}
Original Dictionary (after adding 'c'):  {'a': 1, 'b': [2, 3], 'c': 4}
Deep Copy (after appending 5 to 'b' key): {'a': 1, 'b': [2, 3, 5]}
  1. original_dict는 초기 딕셔너리로 'a' 키에 1을 할당하고 'b' 키에는 리스트 [2,3]를 할당한다.
  2. copy 모듈의 deepcopy() 함수를 사용하여 original_dict의 깊은 복사를 생성하고 이를 deep_copy에 할당한다. 이로써 original_dict와 deep_copy는 완전히 독립적인 객체가 된다.
  3. 원본 딕셔너리 original_dict에 'c' 키를 추가하면 원본 딕셔너리에만 해당 변경이 반영된다. 깊은 복사된 딕셔너리 deep_copy는 이 변경을 반영하지 않는다.
  4. 'b' 키에 연결된 리스트에 5를 추가하면 깊은 복사된 딕셔너리 deep_copy에는 영향을 미치지 않는다. 깊은 복사는 내부 객체까지 새로운 복사본을 생성하였기 때문에 전파되지 않는다.

따라서 깊은 복사를 사용하면 원본 데이터를 완전히 보호하고 변경을 방지할 수 있다.

 

 

3. 마무리


다음은 지금까지 학습한 얕은 복사와 깊은 복사에 대한 간단한 결론이다.

 

얕은 복사(Shallow Copy)

  • 얕은 복사는 데이터 구조의 최상위 요소만 복사하고 내부 요소는 원본과 동일한 참조를 유지한다.
  • 얕은 복사를 수행하는 방법으로 슬라이싱, 'copy' 모듈의 copy() 함수, 혹은 컴프리헨션 등이 사용된다.
  • 내부 객체가 변경되면 원본과 복사본에 모두 영향을 미칠 수 있다.

 

깊은 복사(Deep Copy)

  • 깊은 복사는 데이터 구조의 모든 요소, 포함된 모든 객체와 내부 객체를 새로운 복사본으로 복제한다.
  • 깊은 복사를 수행하는 방법으로 'copy' 모듈의 deepcopy() 함수가 주로 사용된다.
  • 깊은 복사는 원본과 복사본 간의 모든 객체 참조를 분리하여 원본 변경이 복사본에 영향을 미치지 않는다.

따라서, 얕은 복사는 최상위 요소만 복사되고 내부 객체는 공유되지만, 깊은 복사는 모든 객체를 복사하여 완전히 독립적인 복사본을 생성한다. 데이터의 보호화 변경 방지를 고려할 때 얕은 복사와 깊은 복사 중 선택해야 한다.

 

 

 

읽어주셔서 감사합니다.

 

 

728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.