
이 제6부는 실용성과 기본 문법의 균형을 잡는 핵심 챕터입니다.
책상 위 추적(DRY RUN)이란, 코드를 실제로 실행하기 전에, 종이와 연필(또는 머릿속)로 흐름을 따라가며 이해하는 방법입니다.
이를 통해 코드의 로직과 데이터의 흐름을 깊이 이해할 수 있습니다.
특히 프로그래밍을 막 시작한 단계에서는 중첩 루프(이중 for문)에 어려움을 겪는 것이 일반적입니다.
여기서 3가지 패턴을 확실히 익혀두면, 복잡한 루프 처리에 발목을 잡혀 정작 중요한 로직에 집중하지 못하는 문제를 미연에 방지할 수 있습니다.
약간 지루하게 느껴질 수 있지만, 지금 여기서 이해해두면 이후의 학습이 훨씬 수월해집니다.
| 방법 | 설명 |
|---|---|
| 실행(Run) | 코드를 Python으로 실제로 돌린다 |
| DRY RUN | 코드를 돌리지 않고 머릿속 또는 종이 위에서 흐름을 추적한다 |
DRY RUN을 잘하는 사람은, 코드를 읽는 속도와 버그를 찾는 능력이 압도적으로 빠릅니다.
"코드를 보면 결과가 머릿속에 그려진다" 는 수준에 도달하는 것이 목표입니다.
range() 함수 복습중첩 루프를 이해하기 전에, range() 함수를 확인해둡시다.
print(list(range(3))) # [0, 1, 2]
print(list(range(1, 4))) # [1, 2, 3]
print(list(range(0, 6, 2))) # [0, 2, 4] ← 2씩 증가
| 표현식 | 생성되는 값 |
|---|---|
range(3) | 0, 1, 2 |
range(1, 4) | 1, 2, 3 |
range(0, 6, 2) | 0, 2, 4 |
range(n)은 0부터 n-1까지의 정수를 생성합니다.
for i in range(3): # 외측 루프 (챕터: 대항목)
for j in range(3): # 내측 루프 (절: 소항목)
print(f"i={i}, j={j}")
i와 j 모두 독립적으로 range(3) → 0, 1, 2를 순회합니다.
외측 루프가 1바퀴 도는 동안 내측 루프는 항상 3바퀴 돕니다.
목차 구성에 비유하면:
0.0 시작하며
0.1 대상 독자
0.2 목차
1.0 Python이란
1.1 Python 설치 방법
1.2 VSCode 설치 방법
2.0 변수
2.1 리스트
2.2 for문
i = 챕터 번호(0, 1, 2), j = 절 번호(0, 1, 2) - 챕터마다 항상 3개의 절이 존재합니다.
① i=0 진입 → j가 0, 1, 2를 순회
j=0: print("i=0, j=0")
j=1: print("i=0, j=1")
j=2: print("i=0, j=2")
② i=1 진입 → 내측 루프가 j=0부터 다시 시작
j=0: print("i=1, j=0")
j=1: print("i=1, j=1")
j=2: print("i=1, j=2")
③ i=2 진입 → 내측 루프가 j=0부터 다시 시작
j=0: print("i=2, j=0")
j=1: print("i=2, j=1")
j=2: print("i=2, j=2")
추적 결과표:
| i | j | 출력 |
|---|---|---|
| 0 | 0 | i=0, j=0 |
| 0 | 1 | i=0, j=1 |
| 0 | 2 | i=0, j=2 |
| 1 | 0 | i=1, j=0 |
| 1 | 1 | i=1, j=1 |
| 1 | 2 | i=1, j=2 |
| 2 | 0 | i=2, j=0 |
| 2 | 1 | i=2, j=1 |
| 2 | 2 | i=2, j=2 |
총 출력 횟수: 3(외측) × 3(내측) = 9회
💡 핵심 법칙
독립형의 총 실행 횟수 = 외측 루프 횟수 × 내측 루프 횟수
range(3)×range(3)= 3 × 3 = 9회
i에 따라 달라진다패턴1을 이해했다면, "의존형"은 한 가지만 추가로 이해하면 됩니다.
내측 루프의 종료 지점이 i의 값에 따라 변한다 는 점입니다.
for i in range(3):
for j in range(i + 1): # 내측의 종점이, 외측의 i에 따라 바뀐다
print(f"i={i}, j={j}")
목차 구성에 비유하면:
0.0 시작하며 ← 챕터0: 절이 1개
1.0 Python이란
1.1 Python 설치 방법 ← 챕터1: 절이 2개
2.0 변수
2.1 리스트
2.2 for문과 리스트 ← 챕터2: 절이 3개
난이도가 올라갈수록 소항목(절)의 수가 늘어나는 구조입니다.
range(i + 1)이 매 반복마다 어떻게 바뀌는지 먼저 계산합니다.
| i의 값 | range(i+1) | j가 취하는 값 | 내측 루프 횟수 |
|---|---|---|---|
| 0 | range(1) | 0 | 1회 |
| 1 | range(2) | 0, 1 | 2회 |
| 2 | range(3) | 0, 1, 2 | 3회 |
① i=0 진입 → range(0+1) = range(1) → j=0만 실행
j=0: print("i=0, j=0")
② i=1 진입 → range(1+1) = range(2) → j=0, 1 실행
j=0: print("i=1, j=0")
j=1: print("i=1, j=1")
③ i=2 진입 → range(2+1) = range(3) → j=0, 1, 2 실행
j=0: print("i=2, j=0")
j=1: print("i=2, j=1")
j=2: print("i=2, j=2")
추적 결과표:
| i | j | 출력 |
|---|---|---|
| 0 | 0 | i=0, j=0 |
| 1 | 0 | i=1, j=0 |
| 1 | 1 | i=1, j=1 |
| 2 | 0 | i=2, j=0 |
| 2 | 1 | i=2, j=1 |
| 2 | 2 | i=2, j=2 |
총 출력 횟수: 1 + 2 + 3 = 6회
💡 독립형 vs 의존형 비교
독립형 의존형 내측 루프 범위 항상 고정 ( range(3))i에 따라 변함 (range(i+1))총 실행 횟수 3 × 3 = 9회 1 + 2 + 3 = 6회 추적 난이도 쉬움 보통
패턴1~2를 확실히 추적해두었다면, 패턴3은 훨씬 쉽게 느껴질 것입니다.
total = 0 # 상태 초기화
for i in range(3):
for j in range(2):
total += 1 # 상태 업데이트
# 모든 루프(계산)가 끝나고 나서, 마지막에 결과를 출력한다
print(f"총계: {total}")
total += 1은total = total + 1과 같은 의미입니다.
total = 0 이 초기 상태입니다.
루프가 돌면서 total += 1이 실행될 때마다 상태가 업데이트됩니다.
이것은 제5부에서 본 이 코드와 정확히 같은 구조입니다.
disktype_ufo = [] # ← 초기 상태 (빈 리스트)
for row in csv_content.splitlines():
if "원반" in row:
disktype_ufo.append(row) # ← 상태 업데이트 (리스트에 추가)
| 코드 | 초기 상태 | 상태 업데이트 방법 | 최종 상태 |
|---|---|---|---|
| 패턴3 | total = 0 | total += 1 | total = 6 |
| 제5부 | disktype_ufo = [] | .append(row) | 원반 행이 담긴 리스트 |
상태 관리 = 초기값을 설정하고, 루프 안에서 업데이트하고, 루프 후에 사용한다.
range(3) × range(2) → 총 3 × 2 = 6회 실행됩니다.
① i=0 진입 (range(2) → j=0, 1)
j=0: total = 0 + 1 = 1
j=1: total = 1 + 1 = 2
② i=1 진입 (range(2) → j=0, 1)
j=0: total = 2 + 1 = 3
j=1: total = 3 + 1 = 4
③ i=2 진입 (range(2) → j=0, 1)
j=0: total = 4 + 1 = 5
j=1: total = 5 + 1 = 6
추적 결과표:
| i | j | total의 변화 |
|---|---|---|
| 0 | 0 | total = 1 |
| 0 | 1 | total = 2 |
| 1 | 0 | total = 3 |
| 1 | 1 | total = 4 |
| 2 | 0 | total = 5 |
| 2 | 1 | total = 6 |
최종 출력:
총계: 6
| 패턴1: 독립형 | 패턴2: 의존형 | 패턴3: 상태 의존형 | |
|---|---|---|---|
| 특징 | 내측이 항상 고정 범위 | 내측이 i에 따라 변함 | 루프 밖의 변수가 누적 업데이트됨 |
| 핵심 코드 | for j in range(3) | for j in range(i+1) | total += 1 |
| 실전 활용 | 행렬 처리, 좌표 순회 | 삼각형 구조 데이터 | 합계, 카운트, 리스트 수집 |
| 총 실행 횟수 | n × m (고정) | 1+2+...+n (가변) | n × m (고정이지만 상태가 변함) |
아래 코드의 출력 결과를 실행하지 말고 예측해보세요.
그 후에 실제로 실행해서 맞는지 확인해보는 것이 최고의 학습법입니다.
연습 문제 1: 독립형
for i in range(2):
for j in range(4):
print(f"{i}-{j}")
총 몇 줄이 출력될까요? 마지막 줄은 무엇일까요?
연습 문제 2: 의존형
for i in range(4):
for j in range(i):
print(f"★" * j)
총 몇 줄이 출력될까요? (range(i) 이므로 i=0일 때 내측은 0회)
연습 문제 3: 상태 의존형
words = []
for i in range(3):
for j in range(2):
words.append(f"단어{i}-{j}")
print(words)
print(f"총 단어 수: {len(words)}")
words의 최종 내용과 총 단어 수를 예측해보세요.
| 패턴 | 구조 | 핵심 포인트 |
|---|---|---|
| 독립형 | for j in range(고정값) | 내측 범위가 항상 같다 |
| 의존형 | for j in range(i+1) | 내측 범위가 외측 i에 따라 달라진다 |
| 상태 의존형 | 상태 = 초기값 → 루프 안에서 업데이트 | 변수가 루프를 통해 누적·변화한다 |
📌 DRY RUN 습관의 3단계
- 코드를 보고 외측 루프가 몇 번 도는지 먼저 파악한다
- i의 각 값에 대해 내측 루프가 몇 번 도는지 계산한다
- 상태 변수(total, 리스트 등)가 어떻게 바뀌는지 표로 추적한다
©2024-2026 MDRULES.dev, Hand-crafted & made with Jaewoo Kim.
이메일문의: jaewoo@mdrules.dev
AI강의/개발/기술자문, AI 업무 자동화 컨설팅 문의: https://talk.naver.com/ct/w5umt5
AI 프롬프트 및 워크플로우 설계 대행: https://mdrules.dev
📚 다음 단계: 다음 챕터에서는 Velog(기술 블로그)에서 최신 기사 제목을 가져와 AI에게 기술 트렌드를 분석시키는 코드를 살펴봅니다.
지금까지 배운 리스트·for문·상태 관리 패턴이 실전에서 어떻게 조합되는지 직접 확인해보세요.