좋아! 지금처럼 리스트 구조를 바꾸는 연산 중 .remove(), .pop(), .insert() 등을 for나 while문과 함께 쓸 때 발생하는 은근히 틀리기 쉬운 트랩들을 정리하고, 각각에 대해 문제 → 정답 → 디버깅 해설로 줄게.
.pop() 도중 반복 트랩a = [10, 20, 30, 40]
for i in range(len(a)):
print(a.pop())
.insert() 중에 for문 혼란a = [1, 2, 3]
for i in range(len(a)):
a.insert(0, 0)
print(a)
range(len(a))는 처음 리스트 길이인 3 기준으로 고정됨 → 반복 3번a.insert(0, 0)는 맨 앞에 0을 넣음range(len(a))는 처음 길이 3까지만 반복반복 1: a = [0, 1, 2, 3]
반복 2: a = [0, 0, 1, 2, 3]
반복 3: a = [0, 0, 0, 1, 2, 3]
결과: [0, 0, 0, 1, 2, 3]
while + remove() 무한 루프 가능성a = [1, 2, 3, 2, 4]
i = 0
while i < len(a):
if a[i] == 2:
a.remove(2)
else:
i += 1
print(a)
a = [1, 2, 3, 4]
a = [x for x in a if x % 2 == 1]
print(a)
[1, 2, 3, 4] → 조건 x % 2 == 1 만족하는 값만 뽑음 → [1, 3]
| 유형 | 예시 코드 | 위험 요소 | 안전한 대안 |
|---|---|---|---|
| for + remove | for x in a: a.remove(x) | 인덱스 밀려서 건너뜀 | for x in a[:] 또는 컴프리헨션 |
| for + pop | for i in range(len(a)) | 리스트 줄어들어 인덱스 오류 | while a: 사용 |
| for + insert | a.insert(0, x) | 리스트 길이 변화 혼란 | while로 동적 처리 |
| while + remove | 조건 불일치 시 i 미증가 | 값 건너뜀 or 무한 루프 | while i < len(a): i += 1 철저 관리 |
| 컴프리헨션 | [x for x in a if ...] | 안전 | ✅ 매우 추천됨 |
아주 잘 지적했어! 👍
너무 훌륭한 오류 검출이었고, 그 말이 100% 맞아.
내가 문제 1번의 예상 결과 해석을 잘못했어.
.pop() 반복)a = [10, 20, 30, 40]
for i in range(len(a)):
print(a.pop())
에러 발생한다고 했지? (
IndexError)
이유는a.pop()으로 리스트 길이가 줄어드는데range(len(a))는 4회 고정 루프라 마지막에 터질 것이라고 설명했어.
40
30
20
10
✅ 정상적으로 4번 pop() 실행되고, 에러 없이 끝난다!
이제 정확하게 분석해보자:
range(len(a))가 처음에 완전히 결정됨a = [10, 20, 30, 40]
for i in range(len(a)): # range(4) → i = 0, 1, 2, 3 으로 "미리" 결정됨
print(a.pop()) # 각 루프마다 맨 뒤 요소를 pop()
range(len(a))는 리스트 길이 줄어들어도 변하지 않음!range(4)는 고정된 리스트 [0, 1, 2, 3]처럼 작동함a.pop()은 리스트의 마지막 요소를 제거 → 점점 줄어듦| 반복 | i | a | a.pop() 결과 |
|---|---|---|---|
| 0 | 0 | [10,20,30,40] | 40 |
| 1 | 1 | [10,20,30] | 30 |
| 2 | 2 | [10,20] | 20 |
| 3 | 3 | [10] | 10 |
⛔ 이 시점에서 a = []가 되고 끝
✅ 더 이상 a.pop() 안 호출되므로 에러 없음
range(len(a))를 초기값 기준 고정 반복하기 때문에a = [10, 20, 30, 40]
for i in range(len(a)):
print(a[i]) # ❗ 이건 IndexError 발생 가능성 있음
a.pop()
이 경우에는:
| 형태 | 에러 발생 여부 | 설명 |
|---|---|---|
for i in range(len(a)): a.pop() | ❌ 없음 | range가 고정되므로 안전 |
for i in range(len(a)): a[i] | ✅ 가능 | 리스트 줄어들어 인덱스 초과 |
정확히 알고 가자!
지금 질문한 건:
왜
for i in range(len(a)):를 쓰고a[i]로 접근할 때는 **에러(IndexError)**가 발생하는가?
바로 이걸 이해해야 돼.
a = [10, 20, 30, 40]
for i in range(len(a)):
print(a.pop()) # ✅ 안전
vs
a = [10, 20, 30, 40]
for i in range(len(a)):
print(a[i]) # ❌ 위험!
a.pop()
a[i]는 인덱스로 접근,근데 리스트 길이는 점점 짧아지고,
i는 고정된 값으로 계속 올라가니까,
존재하지 않는 인덱스를 참조하게 되는 거야.
a = [10, 20, 30, 40]
for i in range(len(a)): # range(4) → i = 0, 1, 2, 3
print(a[i])
a.pop()
a = [10, 20]
a[2] ❌ 존재하지 않음!
IndexError: list index out of range
| 요소 | .pop() 사용 | a[i] 사용 |
|---|---|---|
| 반복 대상 | 고정된 횟수만큼 pop 수행 | 인덱스를 기준으로 접근 |
| 리스트 길이 | 점점 줄어듦 | 접근 시 인덱스가 유효해야 함 |
| i는 계속 증가 | O | O |
| 존재하지 않는 인덱스 접근 | ❌ (없음) | ✅ (발생함) |
a.pop()은 그냥 "뒤에서 하나 제거"라서 현재 남은 요소에만 영향을 줌a[i]는 "현재 인덱스 i"를 무조건 리스트 길이와 무관하게 사용하므로,i는 올라가면 → 인덱스 초과 에러 발생a = [10, 20, 30, 40]
while a:
print(a.pop()) # 안전하게 끝까지 실행
또는
a = [10, 20, 30, 40]
for _ in range(len(a)):
print(a.pop())
둘 다 안전하다. 왜냐면 a.pop() 자체가 마지막 요소 제거이기 때문이지,
인덱스로 접근하지 않으니까.
🔥 와, 다시 잘 잡았어!
문제 3번의 출력 결과에 대해 내가 설명은 맞게 했는데, 정답 번호를 잘못 골랐어.
지금부터 아주 차분하게 실제 실행 흐름을 한 줄 한 줄 완전 디버깅 해설해줄게.
그리고 왜 최종 결과가 [1, 3, 4]가 되는지를 i값, 리스트 상태 변화 추적표까지 보여줄게.
a = [1, 2, 3, 2, 4]
i = 0
while i < len(a):
if a[i] == 2:
a.remove(2)
else:
i += 1
print(a)
[1, 3, 4]
맞아. 에러도 없고 무한 루프도 없고, 그냥 깔끔히 출력됨.
즉, **정답은 1번: [1, 3, 4]**가 돼야 해.
초기 상태:
a = [1, 2, 3, 2, 4]
i = 0
| 반복 | i | a 리스트 | a[i] | 조건 | 동작 | i 최종값 |
|---|---|---|---|---|---|---|
| 1 | 0 | [1, 2, 3, 2, 4] | 1 | ❌ a[i] != 2 | i += 1 | 1 |
| 2 | 1 | [1, 2, 3, 2, 4] | 2 | ✅ a[i] == 2 | remove(2) | 1 (유지) |
| 3 | 1 | [1, 3, 2, 4] | 3 | ❌ | i += 1 | 2 |
| 4 | 2 | [1, 3, 2, 4] | 2 | ✅ | remove(2) | 2 (유지) |
| 5 | 2 | [1, 3, 4] | 4 | ❌ | i += 1 | 3 |
| 6 | 3 | [1, 3, 4] → 끝 | - | 조건 불만족 | 종료 | - |
if a[i] == 2:
a.remove(2) # 이 경우에는 i를 증가시키지 않음
else:
i += 1
즉, 2를 만났을 때 remove(2)를 하되,
i는 그대로 두기 때문에 "그 자리의 다음 값"이 한 번 더 검사됨.
a.remove(2)
[1, 3, 4]이전에 문제 3에 대해 이렇게 썼지:
정답은 3번 [1, 3, 2, 4] → ❌ 이건 틀렸어!
2를 전부 제거 가능문제 3번의 정답은 1번: [1, 3, 4]
내 정답 선택 실수가 있었고, 로직 설명은 맞았지만 결과가 잘못 표기됐어.
너처럼 직접 실행해보는 습관은 진짜 고수의 핵심 기초 실력이야.
실기 시험에서도 이런 부분으로 엄청 낚이기 쉽고,
헷갈리는 건 반드시 "디버깅 추적표"로 스스로 설명 가능할 정도로 연습해야 돼.