# [Python TIL] 얕은 복사(Shallow copy)와 깊은 복사(Deep copy)

오늘은 Python에서 리스트를 복사할 때 흔히 발생하는 실수를 다뤄보겠습니다.  
리스트를 복사한 후 `reverse()`를 사용했는데, 원본 리스트까지 바뀌는 현상을 본 적이 있나요?

#### ❌ 문제 코드

아래 코드를 실행하면 원본 리스트까지 뒤집혀버리는 문제가 발생해요.

```python
string = list(input())
string_copy = string  # 얕은 복사 (shallow copy)
string_copy.reverse()
print(string, string_copy)
```

예를 들어, `"hello"`를 입력하면 기대한 출력은:

```python
['h', 'e', 'l', 'l', 'o'] ['o', 'l', 'l', 'e', 'h']
```

인데, 실제로는:

```python
['o', 'l', 'l', 'e', 'h'] ['o', 'l', 'l', 'e', 'h']
```

처럼 원본 리스트(`string`)까지 바뀌어버려요.

---

### 왜 이런 일이 발생할까? 🤔

`string_copy = string`은 **얕은 복사(shallow copy)** 로,  
`string_copy`와 `string`이 **동일한 리스트 객체를 가리키게** 돼요.

즉, `string_copy.reverse()`를 호출하면 **원본 리스트도 같이 뒤집히게 됩니다**!

---

### ✅ 원본을 유지하는 해결 방법

원본 리스트를 유지하면서 새로운 리스트를 뒤집고 싶다면 **깊은 복사(deep copy)** 가 필요합니다.

#### 🔹 방법 1: 슬라이싱 활용

```python
string = list(input())
string_copy = string[:]  # 원본을 새로운 리스트로 복사
string_copy.reverse()
print(string, string_copy)
```

💡 `[:]` 슬라이싱을 사용하면 원본과 같은 요소를 가진 **새로운 리스트**가 생성됩니다.

---

#### 🔹 방법 2: `copy()` 메서드 활용

```python
string = list(input())
string_copy = string.copy()  # 새로운 리스트로 복사
string_copy.reverse()
print(string, string_copy)
```

💡 `copy()` 메서드도 리스트의 복사본을 생성해줍니다.

---

#### 🔹 방법 3: `reversed()` 사용

```python
string = list(input())
string_copy = list(reversed(string))  # 새로운 리스트로 변환
print(string, string_copy)
```

💡 `reversed()`는 원본을 수정하지 않고, 뒤집힌 새로운 iterator를 반환합니다.  
이를 `list()`로 변환하면 원본이 유지된 채로 새로운 리스트를 만들 수 있습니다.

---

### 📝 정리

| 방법 | 원본 유지 | 속도 | 가독성 |
| --- | --- | --- | --- |
| `[:]` | ✅ | 빠름 | 직관적 |
| `.copy()` | ✅ | 빠름 | 명확함 |
| `reversed()` | ✅ | 느림 (iterator 변환 필요) | 가장 깔끔 |
