실버를 위한 코딩/파이썬 연습

중첩 리스트와 얕은복사와 깊은복사

forSilver 2025. 5. 7. 04:57
반응형

중첩 리스트와 얕은복사와 깊은복사

중첩 리스트는 리스트 안에 또 다른 리스트가 포함된 구조입니다. 얕은 복사는 바깥 리스트만 복사하고 내부 리스트는 원본과 공유합니다. 반면 깊은 복사는 모든 계층의 리스트를 새로 만들어 원본과 완전히 독립된 구조를 만듭니다.


📌 코드 요약:

L = [1, ['a', ['x', 'y'], 'b'], 3]
  • L은 중첩 리스트를 포함하는 구조입니다.
  • 구성은 다음과 같습니다:
  • L[0] = 1 L[1] = ['a', ['x', 'y'], 'b'] L[2] = 3

📌 인덱싱 흐름:

  1. L[1]
    → ['a', ['x', 'y'], 'b']
  2. L[1][1]
    → ['x', 'y']
    (위 리스트의 두 번째 요소)
  3. L[1][1][1]
    → 'y'
    (그 리스트에서 인덱스 1, 즉 'y'를 추출)

🧠 핵심 개념:

  • 이중, 삼중 리스트 구조일 때, 인덱싱을 단계적으로 접근하면 됩니다.
  • L[1][1][1]은 "리스트 안의 리스트 안의 요소"에 접근하는 전형적인 다차원 인덱싱입니다.

✅ 요약 정리:

표현식 결과 설명
L[0] 1 첫 번째 요소
L[1] ['a', ['x', 'y'], 'b'] 두 번째 요소 (리스트)
L[1][1] ['x', 'y'] 그 안의 두 번째 리스트
L[1][1][1] 'y' 내부 리스트의 두 번째 요소, 즉 'y' 추출

중첩 리스트에서 얕은복사와 깊은복사

L = [1, ['a', ['x', 'y'], 'b'], 3]

처럼 여러 단계로 중첩된 리스트에서는 얕은 복사(shallow copy)깊은 복사(deep copy)의 차이가 매우 뚜렷하게 나타납니다.


🔹 1. 얕은 복사 (shallow copy)의 경우

import copy

L = [1, ['a', ['x', 'y'], 'b'], 3]
shallow = copy.copy(L)
  • shallow는 L의 최상위 리스트만 새로 만들고,
  • 내부 요소인 ['a', ['x', 'y'], 'b']는 여전히 원본과 같은 객체입니다.

확인해보기

shallow[1][1][0] = 'z'
print(L)  # [1, ['a', ['z', 'y'], 'b'], 3]

✅ 내부의 리스트까지는 복사되지 않았기 때문에,
하나의 복사본을 바꾸면 원본도 함께 바뀝니다.


🔹 2. 깊은 복사 (deep copy)의 경우

deep = copy.deepcopy(L)
deep[1][1][0] = 'q'
print(L)  # [1, ['a', ['z', 'y'], 'b'], 3]
print(deep)  # [1, ['a', ['q', 'y'], 'b'], 3]
  • deep은 내부의 리스트들까지 전부 재귀적으로 복사했기 때문에,
  • deep을 변경해도 L은 전혀 영향을 받지 않습니다.


🔍 시각적 구조 비교

L
├── 1
├── ['a', ['x', 'y'], 'b']
│    └── ['x', 'y']
└── 3

shallow (얕은 복사)
└── 내부 구조는 여전히 L의 것과 공유

deep (깊은 복사)
└── 구조 전체가 복제되어 L과 완전히 분리됨

🔒 어떤 경우에 각각을 써야 하나요?

상황 사용 권장
리스트 안에 숫자, 문자열 등만 있을 때 얕은 복사로도 충분
리스트 안에 리스트, 딕셔너리 등 중첩 구조일 때 깊은 복사 권장
원본을 보존하면서 부분 수정해야 할 때 깊은 복사 필수

✅ 마무리 요약

  • copy.copy() → 가장 바깥 객체만 새로 생성, 내부 참조는 공유
  • copy.deepcopy() → 내부 구조 전체를 재귀적으로 복제, 완전 독립

중첩 리스트를 다룰 때는 복사의 방식에 따라 프로그램의 동작이 달라질 수 있습니다. 얕은 복사는 내부 객체를 공유하므로 원본이 함께 변경될 위험이 있고, 깊은 복사는 완전한 분리를 통해 안정성을 확보할 수 있습니다. 구조의 복잡도에 따라 적절한 복사 방식을 선택하는 것이 중요합니다.