[Python 재입문] 7. Python 중첩 for문 완전 정복 - DRY RUN으로 이중 루프 3가지 패턴 단계별 추적

AgentKim·2026년 3월 13일

이 제6부는 실용성과 기본 문법의 균형을 잡는 핵심 챕터입니다.

책상 위 추적(DRY RUN)이란, 코드를 실제로 실행하기 전에, 종이와 연필(또는 머릿속)로 흐름을 따라가며 이해하는 방법입니다.
이를 통해 코드의 로직과 데이터의 흐름을 깊이 이해할 수 있습니다.

특히 프로그래밍을 막 시작한 단계에서는 중첩 루프(이중 for문)에 어려움을 겪는 것이 일반적입니다.
여기서 3가지 패턴을 확실히 익혀두면, 복잡한 루프 처리에 발목을 잡혀 정작 중요한 로직에 집중하지 못하는 문제를 미연에 방지할 수 있습니다.

약간 지루하게 느껴질 수 있지만, 지금 여기서 이해해두면 이후의 학습이 훨씬 수월해집니다.


DRY RUN이란?

방법설명
실행(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까지의 정수를 생성합니다.


패턴 1: 독립형 - 내측이 외측의 영향을 받지 않는다

for i in range(3):      # 외측 루프 (챕터: 대항목)
    for j in range(3):  # 내측 루프 (절: 소항목)
        print(f"i={i}, j={j}")

ij 모두 독립적으로 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개의 절이 존재합니다.


DRY RUN 추적

① 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")

추적 결과표:

ij출력
00i=0, j=0
01i=0, j=1
02i=0, j=2
10i=1, j=0
11i=1, j=1
12i=1, j=2
20i=2, j=0
21i=2, j=1
22i=2, j=2

총 출력 횟수: 3(외측) × 3(내측) = 9회

💡 핵심 법칙
독립형의 총 실행 횟수 = 외측 루프 횟수 × 내측 루프 횟수
range(3) × range(3) = 3 × 3 = 9회


패턴 2: 의존형 - 내측의 범위가 외측 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개

난이도가 올라갈수록 소항목(절)의 수가 늘어나는 구조입니다.


DRY RUN 추적

range(i + 1)이 매 반복마다 어떻게 바뀌는지 먼저 계산합니다.

i의 값range(i+1)j가 취하는 값내측 루프 횟수
0range(1)01회
1range(2)0, 12회
2range(3)0, 1, 23회

① 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")

추적 결과표:

ij출력
00i=0, j=0
10i=1, j=0
11i=1, j=1
20i=2, j=0
21i=2, j=1
22i=2, j=2

총 출력 횟수: 1 + 2 + 3 = 6회

💡 독립형 vs 의존형 비교

독립형의존형
내측 루프 범위항상 고정 (range(3))i에 따라 변함 (range(i+1))
총 실행 횟수3 × 3 = 9회1 + 2 + 3 = 6회
추적 난이도쉬움보통

패턴 3: 상태 의존형 - 루프가 진행되면서 값이 누적된다

패턴1~2를 확실히 추적해두었다면, 패턴3은 훨씬 쉽게 느껴질 것입니다.

total = 0  # 상태 초기화

for i in range(3):
    for j in range(2):
        total += 1  # 상태 업데이트

# 모든 루프(계산)가 끝나고 나서, 마지막에 결과를 출력한다
print(f"총계: {total}")

total += 1total = total + 1 과 같은 의미입니다.


"상태 관리"란?

total = 0초기 상태입니다.
루프가 돌면서 total += 1이 실행될 때마다 상태가 업데이트됩니다.

이것은 제5부에서 본 이 코드와 정확히 같은 구조입니다.

disktype_ufo = []           # ← 초기 상태 (빈 리스트)

for row in csv_content.splitlines():
    if "원반" in row:
        disktype_ufo.append(row)  # ← 상태 업데이트 (리스트에 추가)
코드초기 상태상태 업데이트 방법최종 상태
패턴3total = 0total += 1total = 6
제5부disktype_ufo = [].append(row)원반 행이 담긴 리스트

상태 관리 = 초기값을 설정하고, 루프 안에서 업데이트하고, 루프 후에 사용한다.


DRY RUN 추적

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

추적 결과표:

ijtotal의 변화
00total = 1
01total = 2
10total = 3
11total = 4
20total = 5
21total = 6

최종 출력:

총계: 6

3가지 패턴 종합 비교

패턴1: 독립형패턴2: 의존형패턴3: 상태 의존형
특징내측이 항상 고정 범위내측이 i에 따라 변함루프 밖의 변수가 누적 업데이트됨
핵심 코드for j in range(3)for j in range(i+1)total += 1
실전 활용행렬 처리, 좌표 순회삼각형 구조 데이터합계, 카운트, 리스트 수집
총 실행 횟수n × m (고정)1+2+...+n (가변)n × m (고정이지만 상태가 변함)

DRY RUN을 직접 연습해보자

아래 코드의 출력 결과를 실행하지 말고 예측해보세요.
그 후에 실제로 실행해서 맞는지 확인해보는 것이 최고의 학습법입니다.

연습 문제 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단계

  1. 코드를 보고 외측 루프가 몇 번 도는지 먼저 파악한다
  2. i의 각 값에 대해 내측 루프가 몇 번 도는지 계산한다
  3. 상태 변수(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문·상태 관리 패턴이 실전에서 어떻게 조합되는지 직접 확인해보세요.

profile
AI-fluent liberal arts engineer | AX Consulting | AI Workflow Architect | LLM Engineer | Claude Code | AI강의/개발/기술자문 | AI 업무 자동화 컨설팅

0개의 댓글