Python 의 for 는 iterable 위의 foreach, C 스타일 인덱스 카운터가 아니야. for x in seq: 는 x 를 각 원소에 바인딩. "for i in 0 to n" 같은 거 없어. 인덱스가 필요하면 range(n). 인덱스랑 값 둘 다 필요하면 enumerate(seq). 이거 한번 익히면 머릿속에서 C 스타일 for 를 변환하는 거 멈춰.
enumerate / zip / reversed — 반복 삼총사
enumerate(seq) 는 (인덱스, 값) 페어 yield. zip(a, b, ...) 은 각 iterable 의 원소를 튜플로 짝지어, 가장 짧은 거 끝나면 멈춤. reversed(seq) 는 역순 yield. 조합하면 — for i, (a, b) in enumerate(zip(list1, list2)):. 이 셋이 수동 인덱스 관리 장르 전체를 대체.
while — "뭔가 될 때까지" 의 일꾼
반복 횟수가 미리 안 정해질 때 while. 입력이 매치할 때까지, 조건 만족까지, 큐가 빌 때까지. 3.8+ 의 walrus 연산자 := 가 read-and-test 패턴에 좋아 — while (line := f.readline()):. while True: + 수동 break 손에 닿기 전에 — 조건 직접 while 에 박을 수 있는지 봐.
break / continue / 잘 안 알려진 else
break — 가장 안쪽 loop 종료. continue — 다음 iteration 으로. 이상한 놈 — loop 의 else. else 블록은 loop 가 *break 없이 완주* 했을 때 실행. "뭔가 찾는 중 — 못 찾으면 X 해라" 패턴에 완벽. 처음엔 이상하게 읽혀. 한 번 알면 flag 변수를 깔끔히 대체할 수 있어.
주의: 순회하면서 list 변경하면 버그 자석. 안전한 방법 — 사본 순회 (for x in items[:]) 또는 컴프리헨션으로 새 list 만들고 끝에 교체.
Pythonic Way:for i in range(len(seq)) 쓰는 자신을 발견하면 멈추고 enumerate(seq). range(len()) 이 맞는 유일한 경우는 *값이 진짜로 안 필요할 때* — 그래도 왜 그런지 자문해봐.
Code
iterable 위의 for-each·python
fruits = ["apple", "banana", "cherry"]
# 값 순회
for f in fruits:
print(f)
# 인덱스 같이 — range(len()) 쓰지 말고
for i, f in enumerate(fruits):
print(i, f)
# 시작 인덱스 커스텀
for i, f in enumerate(fruits, start=1):
print(i, f)
# 1 apple
# 2 banana
# 3 cherry
zip — 페어 / 트리플 / 쿼드러플·python
names = ["alice", "bob", "charlie"]
ages = [30, 25, 35]
for name, age in zip(names, ages):
print(f"{name} is {age}")
# zip 은 가장 짧은 거에서 멈춤
tickers = ["AAPL", "MSFT", "GOOG", "NVDA"]
prices = [180, 420, 145]
for t, p in zip(tickers, prices):
print(t, p)
# 3 페어만 출력 — NVDA 는 떨어짐
# zip(strict=True) 는 길이 다르면 raise — 3.10+
try:
for t, p in zip(tickers, prices, strict=True):
pass
except ValueError as e:
print(e)
while + walrus — read-and-test·python
import io
# 파일인 척
f = io.StringIO("line1\nline2\nline3\n")
# 옛 어색한 스타일
# while True:
# line = f.readline()
# if not line:
# break
# process(line)
# 3.8+ walrus — 깔끔
while (line := f.readline()):
print("got:", line.strip())
# got: line1
# got: line2
# got: line3
loop 의 else — break 없을 때 실행·python
def find_negative(items):
for i, x in enumerate(items):
if x < 0:
print(f"first negative at index {i}")
break
else:
print("음수 없음")
find_negative([1, 2, 3]) # 음수 없음
find_negative([1, -2, 3]) # first negative at index 1
# else 는 while 에서도
n = 100
while n > 1:
if n % 2 == 1: # 홀수
print("홀수 만남")
break
n //= 2
else:
print("홀수 없이 끝까지 반")
# 홀수 없이 끝까지 반
순회 중 변경 버그 — 안전한 대안·python
items = [1, 2, 3, 4, 5, 6]
# 위험 — 이상한 동작, 원소 건너뛸 수 있음
# for x in items:
# if x % 2 == 0:
# items.remove(x)
# 안전 1 — 슬라이스 사본 순회
items = [1, 2, 3, 4, 5, 6]
for x in items[:]:
if x % 2 == 0:
items.remove(x)
print(items) # [1, 3, 5]
# 안전 2 — 컴프리헨션으로 새 list
items = [1, 2, 3, 4, 5, 6]
items = [x for x in items if x % 2 != 0]
print(items) # [1, 3, 5]
병렬 list 두 개 — tickers = ["AAPL", "MSFT", "GOOG", "NVDA"], prices = [180, 420, 145, 950]. (a) enumerate + zip 으로 각 ticker + price 출력. (b) 200 미만 가격의 첫 ticker 찾아서 이름 출력 + break. 못 찾으면 loop else 절로 'all expensive' 출력. (c) while + walrus 로 "pippa" 의 각 글자를 한 번에 하나씩 출력 — iter 와 next 써 (it = iter("pippa"); while (ch := next(it, None)):).
Progress
Progress is local-only — sign in to sync across devices.