프로그래밍백엔드 Python 개발자

얕은 복사와 단순 변수 할당의 차이는 무엇인가요? 중첩 데이터 구조(리스트의 리스트)에 적용할 때 copy.copy()는 어떻게 작동하나요?

Hintsage AI 어시스턴트로 면접 통과

답변

변수 할당(예: a = b)은 Python에서 객체를 복사하지 않고, 기존 객체에 대한 새로운 이름(참조)을 생성합니다. 변경된 이름에 대한 변경 사항은 변할 수 있는 객체의 경우 다른 이름에서도 볼 수 있습니다.

얕은 복사(shallow copy)는 copy.copy(obj) 또는 리스트의 슬라이스 [:] 등을 통해서 이루어지며, 새로운 최상위 객체를 생성하지만 내부의 중첩 객체는 참조로 복사됩니다(즉, 두 구조 모두 동일한 하위 컨테이너를 "보게" 됩니다). 중첩 객체를 수정하면, 변경 사항은 두 객체 모두에서 볼 수 있습니다.

예시:

import copy lst1 = [[1,2], [3,4]] lst2 = copy.copy(lst1) # 또는 lst1[:] lst1[0][0] = 100 print(lst2) # [[100, 2], [3, 4]]

lst2는 새로운 리스트지만 첫 번째 요소는 동일한 중첩 리스트입니다.

주의해야 할 질문

질문: lst2 = lst1[:]와 lst2 = copy.copy(lst1)의 차이는 무엇인가요?

답변: 일반적인(1차원) 리스트에 대해서는 실제로 차이가 없으며, 두 방법 모두 리스트의 얕은 복사를 수행합니다. 그러나 사용자 정의 컨테이너 클래스를 사용하는 경우, 서로 다른 동작을 일으킬 수 있습니다(예: 자신의 __copy__ 메서드가 구현된 경우). dict, set 등 다른 유형의 경우 전문 모듈 copy를 사용하는 것이 더 안전합니다.

import copy lst1 = [1, 2, 3] lst2 = lst1[:] lst3 = copy.copy(lst1) print(lst2 == lst3) # True

주의하지 않음으로 인한 실제 오류 사례


이야기

설정 처리 프로젝트에서 개발자는 기본 매개변수를 params = default_params로 할당하여 "격리"되어 변경될 것이라 예상했습니다. 결국, 어느 복사본에서든 변경이 이루어지면 응용 프로그램의 모든 부분에서 연쇄적으로 변경되었습니다. 그 이유는 사실상 하나의 객체로 작업한 것이었습니다.


이야기

경험이 부족한 프로그래머는 게임 상태를 저장하기 위해 리스트의 얕은 복사를 사용했습니다(game_states = states[:]). 중첩 구조(보드의 조각 리스트)의 경우 한 상태 내의 변경 사항이 다른 상태로 "흐르는" 결과를 초래하여 롤백 및 이동 재현 기록이 깨졌습니다.


이야기

객체 지향 응용 프로그램에서 데이터를 복제하려고 할 때, 슬라이스와 copy.copy() 사이에서 선택해야 했습니다. 하지만 구조 내에서 자신의 복사 메서드를 가진 클래스가 존재했고, 이는 copy.copy()를 사용할 때만 고려되었습니다. 슬라이스는 객체 복사의 논리를 무시하여 명백하지 않은 버그가 발생했습니다.