누구나 로고
Online CoursesFor BusinessLibraryTrend InsightsFree coursesNoticesContactCareers
모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.
로그인무료 회원가입
강좌파이썬 기초 40강 — 처음 배우는 프로그래밍14강

14강 / 전체 14강

for 루프 — 이터레이션 프로토콜의 깊은 이해

9분 읽기 조회 1

for 루프의 내부 동작인 이터레이터 프로토콜을 이해하고 enumerate·zip을 마스터한다.

🎯 이 강의에서 배우는 것

파이썬의 for 루프는 C 언어의 for 루프와 근본적으로 다릅니다. 파이썬의 for는 이터레이터 프로토콜(iterator protocol)을 기반으로 동작합니다. 이 원리를 이해하면 왜 for가 리스트, 문자열, 파일, 제너레이터 등 모든 것에 동작하는지 알 수 있습니다.

🔄 for 루프의 내부 동작

# 이 코드가 내부적으로 어떻게 동작하는가:
for x in [1, 2, 3]:
    print(x)

# 실제로 일어나는 일:
_iter = iter([1, 2, 3])    # 1. __iter__() 호출 → 이터레이터 생성
while True:
    try:
        x = next(_iter)    # 2. __next__() 호출 → 다음 값
        print(x)           # 3. 루프 본문 실행
    except StopIteration:  # 4. 더 없으면 StopIteration → 루프 종료
        break

# iter()와 next()로 수동 이터레이션
lst = [10, 20, 30]
it = iter(lst)          # 이터레이터 생성
print(next(it))         # 10
print(next(it))         # 20
print(next(it))         # 30
try:
    print(next(it))     # StopIteration!
except StopIteration:
    print("다 꺼냈음")

🔍 이터러블 vs 이터레이터

# 이터러블(Iterable): __iter__() 메서드를 가진 객체
# for 문에 쓸 수 있음
# list, str, dict, set, tuple, range, 파일 객체 등

# 이터레이터(Iterator): __iter__() + __next__() 모두 가진 객체
# 이터러블에서 iter()로 생성
# 한 번 소진되면 재사용 불가

# 리스트는 이터러블이지만 이터레이터가 아님
lst = [1, 2, 3]
print(hasattr(lst, "__iter__"))    # True — 이터러블
print(hasattr(lst, "__next__"))    # False — 이터레이터 아님

# 리스트에서 이터레이터 생성
it = iter(lst)
print(hasattr(it, "__iter__"))    # True
print(hasattr(it, "__next__"))    # True — 이터레이터

# 중요: 이터레이터는 한 번만 순회 가능!
it = iter([1, 2, 3])
for x in it:
    print(x)   # 1, 2, 3

for x in it:   # 이미 소진됨
    print(x)   # 아무것도 출력 안 됨!

# 반면 이터러블은 몇 번이든 순회 가능
for x in lst:
    print(x)   # 1, 2, 3

for x in lst:
    print(x)   # 또 1, 2, 3

📏 range() 객체 — Lazy 시퀀스

import sys

# range는 숫자를 미리 만들지 않음 — lazy 객체
r = range(1_000_000_000)   # 10억짜리 range, 즉시 생성!
print(sys.getsizeof(r))    # 48 bytes (크기와 무관하게 일정)
print(sys.getsizeof(list(range(1000))))  # 8056 bytes (실제 리스트)

# range 매개변수
for i in range(5):          # 0, 1, 2, 3, 4
    print(i, end=" ")
print()

for i in range(1, 6):       # 1, 2, 3, 4, 5
    print(i, end=" ")
print()

for i in range(0, 10, 2):  # 0, 2, 4, 6, 8 (step=2)
    print(i, end=" ")
print()

for i in range(10, 0, -1): # 10, 9, 8, ..., 1 (역순)
    print(i, end=" ")
print()

# range의 멤버십 테스트는 O(1)
print(999999 in range(1_000_000))    # True, 즉시!
# 리스트였다면 O(n) 순차 탐색

🔢 enumerate() — 인덱스와 값을 동시에

fruits = ["사과", "바나나", "체리"]

# 나쁜 방법: 인덱스 수동 관리
i = 0
for fruit in fruits:
    print(f"{i}: {fruit}")
    i += 1

# 파이썬다운 방법: enumerate()
for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")
# 0: 사과
# 1: 바나나
# 2: 체리

# start 파라미터: 시작 번호 지정
for num, fruit in enumerate(fruits, start=1):
    print(f"{num}번: {fruit}")
# 1번: 사과
# 2번: 바나나
# 3번: 체리

# enumerate 내부 원리: 카운터를 가진 이터레이터
it = enumerate(["a", "b", "c"])
print(next(it))   # (0, 'a')
print(next(it))   # (1, 'b')

🤐 zip() — 여러 이터러블 병렬 순회

names = ["홍길동", "이순신", "강감찬"]
scores = [85, 92, 78]
grades = ["B", "A", "C"]

# zip: 여러 이터러블을 동시에 순회
for name, score, grade in zip(names, scores, grades):
    print(f"{name}: {score}점 ({grade})")
# 홍길동: 85점 (B)
# 이순신: 92점 (A)
# 강감찬: 78점 (C)

# 가장 짧은 이터러블에서 멈춤
a = [1, 2, 3]
b = [10, 20]
for x, y in zip(a, b):
    print(x, y)   # (1,10), (2,20) — 3은 무시됨

# itertools.zip_longest: 긴 것에 맞춰 None으로 채움
from itertools import zip_longest
for x, y in zip_longest(a, b, fillvalue=0):
    print(x, y)   # (1,10), (2,20), (3,0)

# zip 활용 패턴
keys = ["name", "age", "city"]
values = ["홍길동", 30, "서울"]
person = dict(zip(keys, values))
print(person)  # {'name': '홍길동', 'age': 30, 'city': '서울'}

# 전치행렬 (zip(*matrix))
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed = list(zip(*matrix))
print(transposed)  # [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

🔁 중첩 for 루프와 시간 복잡도

# 이중 루프: O(n^2)
n = 4
for i in range(n):
    for j in range(n):
        print(f"({i},{j})", end=" ")
    print()

# 딕셔너리로 O(n^2)→O(n) 최적화
# 두 수의 합(Two Sum) 문제
def two_sum_slow(nums, target):
    # O(n^2): 모든 쌍을 확인
    for i in range(len(nums)):
        for j in range(i+1, len(nums)):
            if nums[i] + nums[j] == target:
                return [i, j]
    return []

def two_sum_fast(nums, target):
    # O(n): 딕셔너리로 이미 본 값 저장
    seen = {}   # {값: 인덱스}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i
    return []

import time
nums = list(range(10000)) + [9999, 1]
target = 20000

start = time.perf_counter()
two_sum_slow(nums, target)
print(f"O(n^2): {time.perf_counter()-start:.4f}초")

start = time.perf_counter()
two_sum_fast(nums, target)
print(f"O(n):   {time.perf_counter()-start:.4f}초")

⚠️ 자주 하는 실수

  • for 루프에서 리스트를 수정: 순회 중인 리스트를 수정하면 예상치 못한 결과. 복사본을 순회하거나 리스트 컴프리헨션을 사용하세요.
  • 이터레이터를 두 번 순회: 이터레이터는 소진되면 빈 루프. list()로 변환하거나 다시 iter()로 생성하세요.
  • 인덱스 수동 관리: i = 0; for x in lst: ...; i += 1 대신 enumerate()를 사용하세요.

📝 정리 및 다음 강의 예고

  • for 루프는 내부적으로 iter() → next() → StopIteration 패턴으로 동작합니다.
  • 이터러블(반복 가능)과 이터레이터(한 번 순회)의 차이를 명확히 이해하세요.
  • enumerate()와 zip()으로 인덱스를 수동 관리하지 않아도 됩니다.

다음 강의: 루프 제어 키워드 break, continue, pass와 파이썬 고유의 for-else/while-else 패턴을 완전히 이해합니다.

관련 주제

  • 이터레이터 프로토콜
  • iter()·next()·StopIteration
  • range() lazy 시퀀스
  • enumerate()
  • zip() 병렬순회
  • 중첩 for 루프 복잡도
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 파이썬 기초 40강 — 처음 배우는 프로그래밍
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나
이전 13강while 루프 — 반복의 본질과 루프 설계

댓글

0/1000

불러오는 중...

목차

  1. 1.컴퓨터는 어떻게 생각하는가 — 0과 1에서 프로그램까지
  2. 2.파이썬 생태계와 개발 환경 완전 설정
  3. 3.파이썬의 실행 모델 — 바이트코드, PVM, GIL
  4. 4.첫 프로그램 — print()와 input()으로 배우는 I/O 원리
  5. 5.변수란 무엇인가 — 이름표, 객체, 참조의 삼각관계
  6. 6.정수(int) 완전 해부 — 임의 정밀도, 비트 연산, 정수 연산의 함정
  7. 7.부동소수점(float)의 함정 — IEEE 754와 수치 오류의 진실
  8. 8.문자열(str) 완전 해부 — 유니코드, 불변성, 인코딩
  9. 9.불리언(bool)과 None — 진리값 시스템의 철학
  10. 10.연산자 완전 분석 — 우선순위, 결합성, 연산자 오버로딩 예고
  11. 11.f-string과 문자열 포맷팅 완전 정복
  12. 12.조건문 — 프로그램이 결정을 내리는 방법
  13. 13.while 루프 — 반복의 본질과 루프 설계
  14. 14.for 루프 — 이터레이션 프로토콜의 깊은 이해

Support

  • Notices
  • FAQ
  • Contact Us
  • Community

Help & Info

  • Terms of Service
  • Privacy Policy
  • Refund Policy

Services

  • About Us
  • Sign up
  • New courses
  • Free courses
누구나 로고
Terms of ServicePrivacy PolicyRefund Policy

상호명: NUGUNA  |  대표자: 정우진  |  사업자등록번호: 392-32-01817  |  통신판매업신고: 제 2026-서울양천-0564 호

주소: 서울특별시 양천구 목동서로 100  |  이메일: nugunapass@gmail.com  |  전화: 010-6395-3043

© 2026 NUGUNA. All rights reserved.

KB예금주인증관리자
HomeCoursesLibraryContactMY