
파이썬을 활용한 인공지능(AI) 모델 개발이나 대규모 시스템 설계 시, 개발자는 수많은 설정 값(Hyperparameters)과 상태 정보를 객체에 담아 관리하게 됩니다. 이때 흔히 발생하는 치명적인 실수 중 하나가 바로 객체의 '복사(Copy)' 매커니즘을 오해하는 것입니다. 단순히 config_b = config_a라고 선언하거나 얕은 복사(Shallow Copy)를 수행했을 때, 의도치 않게 원본 모델의 가중치나 설정 파일이 오염되는 사이드 이펙트가 발생합니다. 본 포스팅에서는 Shallow Copy와 Deep Copy의 메모리 참조 구조적 차이를 명확히 규명하고, 복잡한 중첩 객체 구조에서 발생하는 데이터 무결성 문제를 안전하게 해결하는 7가지 실무 패턴을 상세히 다룹니다.
1. 객체 복사의 3단계 계층 구조 및 차이점 비교
파이썬의 할당과 복사는 메모리 주소를 어떻게 처리하느냐에 따라 세 가지 수준으로 나뉩니다. 특히 리스트 내부의 리스트, 혹은 클래스 내부의 인스턴스가 존재할 때 그 차이가 극명해집니다.
| 복사 유형 | 참조 방식 (Reference) | 중첩 객체(Nested) 영향 | 메모리 효율 |
|---|---|---|---|
| 단순 할당 (=) | 동일한 메모리 주소 공유 | 원본 수정 시 복사본도 즉시 변경 | 최상 (추가 메모리 미사용) |
| 얕은 복사 (Shallow) | 최상위 껍데기만 새로 생성 | 내부 중첩 객체는 원본과 공유 | 보통 (최상위만 생성) |
| 깊은 복사 (Deep) | 모든 계층의 객체를 새로 생성 | 원본과 완벽히 독립된 개체 | 낮음 (전체 재귀 복사) |
2. 복잡한 모델 설정 해결을 위한 7가지 실무 Sample Examples
딥러닝 실험 관리나 복잡한 클래스 구조를 가진 프로젝트에서 즉시 활용 가능한 코드 예제입니다.
Example 1: 얕은 복사(copy.copy)의 치명적 결함 해결
딕셔너리 내부에 리스트가 포함된 모델 설정값의 경우, 얕은 복사는 내부 리스트를 공유하여 실험 결과를 왜곡시킵니다.
import copy
# 원본 모델 설정 (중첩 구조)
base_config = {
"model_name": "ResNet50",
"layers": [64, 128, 256],
"params": {"lr": 0.01}
}
# 얕은 복사 수행
shallow_config = copy.copy(base_config)
# 문제 발생: 내부 리스트를 수정하면 원본도 변함
shallow_config["layers"][0] = 32
print(f"Original layers: {base_config['layers']}") # [32, 128, 256] -> 오염됨
Example 2: 깊은 복사(copy.deepcopy)를 통한 실험 독립성 확보
서로 다른 하이퍼파라미터로 여러 모델을 동시에 테스트할 때 반드시 사용해야 하는 패턴입니다.
# 깊은 복사 수행
deep_config = copy.deepcopy(base_config)
# 내부의 딕셔너리나 리스트를 수정해도 원본은 안전함
deep_config["params"]["lr"] = 0.0001
print(f"Original LR: {base_config['params']['lr']}") # 0.01
print(f"DeepCopy LR: {deep_config['params']['lr']}") # 0.0001
Example 3: 클래스 인스턴스 복사 시의 사이드 이펙트 방지
클래스 내부에 다른 클래스의 인스턴스가 멤버로 있을 때 얕은 복사는 동일한 멤버 객체를 가리키게 됩니다.
class Optimizer:
def __init__(self, name):
self.name = name
class Model:
def __init__(self, opt):
self.optimizer = opt
opt_adam = Optimizer("Adam")
m1 = Model(opt_adam)
# 얕은 복사 시 m2.optimizer는 m1.optimizer와 같은 주소임
m2 = copy.copy(m1)
m2.optimizer.name = "SGD"
print(m1.optimizer.name) # "SGD" -> 의도치 않은 변경 해결 필요
Example 4: __deepcopy__ 매직 메서드 커스텀 정의 방법
너무 큰 데이터(예: 거대 가중치 행렬)를 복사할 때, 특정 부분만 선택적으로 복사하여 성능을 최적화하는 방법입니다.
class LargeModel:
def __init__(self, weights, config):
self.weights = weights # 매우 큰 데이터
self.config = config
def __deepcopy__(self, memo):
# 가중치는 참조만 하고 설정값만 새로 복사하도록 설계
new_obj = LargeModel(self.weights, copy.deepcopy(self.config, memo))
return new_obj
Example 5: 슬라이싱([:])을 이용한 1차원 리스트 고속 복사
중첩되지 않은 단순 리스트라면 copy.copy보다 슬라이싱이 성능 면에서 유리합니다.
# 1차원 리스트의 경우 가장 빠른 복사 방법
simple_list = [1, 2, 3, 4, 5]
copied_list = simple_list[:]
copied_list[0] = 99
print(simple_list[0]) # 1 (원본 유지)
Example 6: 딕셔너리 .copy() 메서드와 중첩의 한계 해결
딕셔너리의 내장 .copy() 역시 얕은 복사임을 명확히 인지하고 대응해야 합니다.
d1 = {"a": [1, 2], "b": 3}
d2 = d1.copy()
# d2["b"] = 10 -> d1에 영향 없음 (불변 객체이므로)
# d2["a"].append(3) -> d1에 영향 있음 (가변 중첩 객체이므로)
Example 7: JSON 직렬화를 이용한 순수 데이터 깊은 복사 트릭
복잡한 클래스 기능이 필요 없고 '데이터'만 깊은 복사를 하고 싶을 때 활용하는 속도 위주의 편법입니다.
import json
data = {"id": 1, "meta": {"tags": ["AI", "Python"]}}
# 직렬화 후 다시 로드하면 완벽한 독립 객체가 됨 (단, 메서드 등은 소실)
quick_deep_copy = json.loads(json.dumps(data))
3. 메모리 누수 및 성능 저하 방지를 위한 가이드
deepcopy는 편리하지만, 수백만 개의 객체가 얽힌 구조에서는 재귀 호출로 인해 RecursionError를 발생시키거나 메모리 점유율을 급격히 높일 수 있습니다.
- 순환 참조 주의: 객체 A가 B를 참조하고 B가 다시 A를 참조할 때
deepcopy는 이를 추적하지만 연산 비용이 비쌉니다. - 불변 객체 활용: 설정값에
tuple이나frozenset을 사용하면 복사 오버헤드 자체를 줄일 수 있습니다. - 메모리 맵 활용: 대형 모델 가중치는 복사 대신
numpy.memmap이나SharedMemory를 고려하십시오.
4. 결론
파이썬의 Shallow Copy와 Deep Copy는 단순한 문법적 차이를 넘어 데이터의 생명 주기를 결정짓는 핵심 개념입니다. 특히 딥러닝 모델의 하이퍼파라미터 튜닝이나 객체 지향 설계를 할 때, 중첩된 가변 객체가 있다면 반드시 copy.deepcopy를 사용하거나 객체를 새롭게 생성하는 팩토리 패턴을 도입하여 데이터 오염을 원천 차단해야 합니다.
[내용 출처 및 참고 문헌]
- Python Standard Library Documentation - "copy — Shallow and deep copy operations."
- Fluent Python by Luciano Ramalho - "Chapter 6: Object References, Mutability, and Recycling."
- Real Python - "Shallow vs Deep Copying of Python Objects."
- Brett Slatkin, "Effective Python: 90 Specific Ways to Write Better Python."
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] 가변 객체와 불변 객체의 인자 전달 차이점 및 사이드 이펙트 해결 방법 7가지 (0) | 2026.04.12 |
|---|---|
| [PYTHON] 만든 AI 모델을 웹 사이트에 올리는 7가지 방법과 Flask vs FastAPI 결정적 차이 해결 (0) | 2026.04.11 |
| [PYTHON] 모델 배포 시 서빙(Serving)의 3가지 핵심 개념과 성능 해결 방법 7가지 (0) | 2026.04.11 |
| [PYTHON] 딥러닝 모델의 크기를 90% 줄이는 실무 경량화 방법과 7가지 해결 전략 (0) | 2026.04.11 |
| [PYTHON] 머신러닝 모델을 REST API로 배포하는 7가지 방법과 성능 해결 차이점 분석 (0) | 2026.04.11 |