제어 흐름 — if, while, for, match-case
들여쓰기로 블록을 만드는 흐름 제어, range/enumerate/zip, 그리고 switch와 동작 방식이 다른 match-case 패턴 매칭까지 정리합니다.
2장 변수, 기본 타입과 타입 힌트에서 만든 변수들을 가지고, 본 챕터에서는 흐름을 만들어 보겠습니다. if, while, for, 그리고 3.10에서 들어온 match-case 까지입니다.
뒤에 자주 만나게 될 match-case가 본 챕터의 핵심 포인트입니다. 다른 언어의 switch와는 동작 방식이 달라 처음에는 낯설지만, 한 번 익숙해지면 JSON / 이벤트 / DTO 분기 코드가 짧고 안전해집니다. 13장 패턴 매칭 깊이에서 본격적으로 다시 다룹니다.
파이썬 흐름 제어의 큰 특징은 두 가지입니다.
- 블록은 들여쓰기로 구분합니다. 중괄호
{}가 없습니다. - 콜론(
:)으로 헤더를 끝냅니다.if x > 0:처럼.
그래서 들여쓰기가 곧 문법입니다. 일반적으로 공백 4칸을 씁니다 (PEP 8). 탭과 스페이스를 섞어 쓰면 에러가 납니다.
if / elif / else
#
다른 언어와 가장 비슷합니다. 괄호가 없는 게 차이.
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
print(grade) # Belse if가 아니라 **elif**입니다. 왜 합쳤는지는 역사적 이유이며, 외워두면 됩니다.
한 줄짜리 — 삼항 연산자 #
C 계열의 cond ? a : b와 다릅니다. 파이썬은 a if cond else b 형태입니다.
status = "성인" if age >= 19 else "미성년"자연어 가까운 순서라 처음에는 어색하지만, 익숙해지면 읽기 좋습니다.
진리값과 조건 — falsy 활용 #
2장에서 본 falsy 값들을 그대로 활용합니다.
items: list[int] = []
if not items:
print("비어 있음") # 이게 출력됨
# 아래도 같은 의미지만, 위가 더 파이써닉
if len(items) == 0:
print("비어 있음")리스트 비었음 검사로 len(x) == 0을 쓰는 건 보통 not x로 줄입니다.
is와 ==
#
이건 주의가 필요한 부분입니다.
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True (값이 같음)
print(a is b) # False (다른 객체)
x = None
print(x is None) # True ← None 비교는 항상 is==은 값 비교, is는 객체 동일성 비교입니다. None, True, False는 항상 is로 비교하세요. 다른 값은 ==입니다.
while
#
조건이 참인 동안 반복.
count = 0
while count < 5:
print(count)
count += 1++는 없습니다. count += 1입니다.
break, continue
#
n = 0
while True:
n += 1
if n % 2 == 0:
continue # 짝수는 건너뜀
if n > 7:
break # 7 넘으면 끝
print(n)
# 1, 3, 5, 7while True + break는 “조건이 복잡해서 위쪽에 적기 어려운” 무한 루프 패턴입니다. 흔히 씁니다.
else 절 — 잘 안 알려진 기능
#
while, for에는 else가 붙을 수 있습니다. “루프가 break 없이 끝났을 때” 실행됩니다.
n = 0
while n < 10:
if n == 99:
break
n += 1
else:
print("break 없이 끝났음") # 이게 출력흔하지는 않지만 “찾는 값이 없어서 다 돌았을 때"를 처리하기에 깔끔한 경우가 있습니다. 너무 많이 쓰면 가독성이 오히려 떨어지니 적당히.
for — 모두 시퀀스 순회
#
다른 언어의 for (i = 0; i < n; i++) 같은 C 스타일은 없습니다. 파이썬의 for는 항상 이터러블을 순회 합니다.
names = ["a", "b", "c"]
for name in names:
print(name)문자열도 이터러블입니다.
for ch in "hello":
print(ch)
# h, e, l, l, o11장 이터러블, 제너레이터, yield from에서 for in이 어떤 객체에 동작하는지(__iter__ / __next__ 프로토콜) 깊이 다룹니다.
range — 숫자 시퀀스가 필요할 때
#
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 7): # 2, 3, 4, 5, 6
print(i)
for i in range(0, 10, 2): # 0, 2, 4, 6, 8 (step 2)
print(i)range(start, stop, step)입니다. stop은 포함되지 않습니다 (반-개방 구간). 이게 처음에 헷갈리지만, 다른 언어 슬라이스와 같은 관례라 곧 익숙해집니다.
enumerate — 인덱스가 필요할 때
#
items = ["사과", "배", "감"]
for i, item in enumerate(items):
print(f"{i}: {item}")
# 0: 사과
# 1: 배
# 2: 감for i in range(len(items)) 후 items[i]로 꺼내는 건 안티패턴입니다. enumerate 한 단어로 끝납니다.
zip — 여러 리스트 동시 순회
#
names = ["커티스", "스미스", "존"]
ages = [30, 25, 40]
for name, age in zip(names, ages):
print(f"{name}: {age}")길이가 다르면 짧은 쪽에 맞춰 끊깁니다. 길이 안 맞을 때 에러를 내고 싶으면 zip(..., strict=True) (3.10+).
for n, a in zip(names, ages, strict=True):
...패턴 매칭 — match-case (3.10+)
#
switch와 모양은 비슷한데, 할 수 있는 일이 훨씬 많습니다. 파이썬은 단순 분기가 아니라 패턴 매칭으로 설계됐습니다.
가장 단순한 형태 #
def http_status(code: int) -> str:
match code:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Server Error"
case _:
return "Unknown"case _:가 와일드카드(default)입니다. JavaScript의 default:에 해당합니다.
여러 값 한 케이스로 — |
#
def category(code: int) -> str:
match code:
case 200 | 201 | 204:
return "성공"
case 400 | 401 | 403 | 404:
return "클라이언트 오류"
case 500 | 502 | 503:
return "서버 오류"
case _:
return "기타"구조 분해 — 여기서부터 중요 #
리스트, 튜플, 딕셔너리의 모양 자체를 패턴으로 쓸 수 있습니다.
def describe(point: tuple[int, ...]) -> str:
match point:
case ():
return "빈 점"
case (x,):
return f"1D: {x}"
case (x, y):
return f"2D: ({x}, {y})"
case (x, y, z):
return f"3D: ({x}, {y}, {z})"
case _:
return "고차원"
print(describe((1, 2))) # 2D: (1, 2)
print(describe((1, 2, 3))) # 3D: (1, 2, 3)각 패턴 안의 x, y는 해당 위치의 값을 변수에 바인딩 합니다. 매칭과 동시에 변수가 만들어집니다. JavaScript 구조 분해 + switch가 한곳에 합쳐진 형태.
딕셔너리 패턴 #
event = {"type": "click", "x": 100, "y": 200}
match event:
case {"type": "click", "x": x, "y": y}:
print(f"클릭: ({x}, {y})")
case {"type": "key", "code": code}:
print(f"키: {code}")
case _:
print("알 수 없는 이벤트")특정 키가 존재하고 그 값을 변수로 가져오는 패턴. API 응답 처리에 잘 맞습니다.
가드 — if 조건 추가
#
match (x, y):
case (a, b) if a == b:
print(f"동일: {a}")
case (a, b) if a > b:
print(f"a 가 큼")
case _:
print("그 외")클래스 패턴 #
class Circle:
def __init__(self, radius: float):
self.radius = radius
class Square:
def __init__(self, side: float):
self.side = side
shape = Circle(5)
match shape:
case Circle(radius=r):
print(f"원, 반지름 {r}")
case Square(side=s):
print(f"정사각형, 한 변 {s}")타입 검사 + 속성 추출이 한 줄에 들어갑니다.
switch와 동작 방식이 다른 이유
#
match-case는 단순한 다중 분기가 아니라 자료의 모양으로 분기하는 도구입니다. 위 코드를 if-elif로 다시 쓰면 길고 어색해집니다.
if isinstance(shape, Circle):
r = shape.radius
print(f"원, 반지름 {r}")
elif isinstance(shape, Square):
s = shape.side
print(f"정사각형, 한 변 {s}")같은 동작인데 타입 체크와 속성 꺼내기가 따로따로입니다. match는 이 두 단계를 합쳐 한 줄로 표현합니다. JSON / 이벤트 객체 처리에서 효용이 큽니다.
본 챕터에서는 표층만 살펴보겠습니다. 13장 패턴 매칭 깊이에서 시퀀스 / 매핑 / 클래스 패턴의 정확한 규칙과 실전 사용처를 다시 다룹니다.
흐름의 진실 — pass
#
블록이 비어 있을 수가 없습니다. 들여쓰기 블록이 없으면 문법 오류입니다. 일단 비워두고 싶을 때 **pass**를 씁니다.
def todo():
pass # 나중에 구현
if x > 0:
pass # 일단 무시
else:
handle(x)... (Ellipsis 객체)도 같은 용도로 종종 보이지만, **pass**가 더 관습적입니다.
for도 컴프리헨션이라는 패턴이 있다
#
리스트, 딕셔너리, 세트를 만들 때 for를 한 줄에 압축하는 문법이 있습니다.
squares = [x ** 2 for x in range(5)]
# [0, 1, 4, 9, 16]다음 4장 컬렉션과 컴프리헨션에서 본격적으로 다룹니다.
연습문제 #
pyright가 설치된 프로젝트에서def grade(score: int) -> str:시그니처의 함수를 작성하세요. 90 이상 “A”, 80 이상 “B”, 70 이상 “C”, 그 외 “F"를 반환합니다.if-elif-else1개와match-case1개 두 버전을 모두 작성하고 동작이 같은지 확인합니다.dict[str, int | str]타입의event변수에{"type": "click", "x": 100, "y": 200}또는{"type": "key", "code": "Enter"}또는{"type": "scroll", "dx": 0, "dy": -10}셋 중 하나가 들어옵니다.match-case와 dict 패턴으로 분기해 각각 다른 메시지를 출력하는handle(event)함수를 작성하세요.names = ["커티스", "스미스", "존"]과ages = [30, 25, 40]를enumerate+zip을 조합해0: 커티스(30),1: 스미스(25),2: 존(40)으로 출력하세요. 길이가 다르면 에러가 나도록strict=True를 적용합니다.
한 줄 요약: 파이썬 흐름 제어는 들여쓰기 + 콜론.
if/elif/else,while,for in이 기본이고,for의 동반자range/enumerate/zip가 일상의 90% 다.match-case는 단순 switch가 아니라 자료 모양으로 분기하는 도구이며, JSON / 이벤트 / 클래스 분기에서 특히 유용하다.
다음 챕터 #
다음 4장 컬렉션과 컴프리헨션에서는 가장 많이 쓰이는 자료 구조 4개 — list, tuple, dict, set과, 그것들을 한 줄로 만드는 컴프리헨션을 다룹니다. 본 챕터의 for가 컴프리헨션의 기반이 됩니다.