학습 순서 3번. 프로그램이 처음으로 판단을 하기 시작합니다. 이 저장소의 마지막 챕터입니다.
if/if~else/if~elif~else/ 중첩if를 단계적으로 익힌다- 3항 연산자로 한 줄 조건문을 쓴다
- 파이썬에
switch가 없다는 것과,dict로 흉내 내는 방법을 안다 random모듈로 난수를 만든다sys.argv로 명령행 인자를 받는다
randomEx.py 난수 7종
ifex/
ifEx0_scratch.py 저장소 맨 위에 있던 13줄 습작 (아래 참고)
ifEx1.py ★ if 문 4단계 발전 과정이 주석으로 층층이 쌓여 있음
ifEx2.py 중첩 if
ifEx3.py 연습문제 — 크기·홀짝·부호 판정 ⚠️ 결함 있음
ifEx4.py 연습문제 — 3과목 합격 판정 ⚠️ 결함 있음
switchex/
switchEx.py dict.get() 으로 switch 흉내
inputex/
argvEx.py sys.argv
inputTest3.py input() 복습
inputTest4.py 연습문제 — 원의 둘레·넓이
ifEx0_scratch.py는 원래 저장소 루트에ifEX1.py라는 이름으로 있었습니다. 같은 폴더의ifEx1.py와 대소문자만 다르고 내용은 전혀 달라 헷갈리기 딱 좋았습니다. 내용은 그대로 두고 이름과 위치만 정리했습니다. 문자열 비교와%10s/{0:<10}자릿수 맞추기를 처음 시험해 본 흔적입니다.
python3 step03_controlstmt/randomEx.py # 입력 불필요
python3 step03_controlstmt/ifex/ifEx1.py # 입력 불필요
python3 step03_controlstmt/switchex/switchEx.py # 입력 불필요
python3 step03_controlstmt/ifex/ifEx4.py # ← 점수 3개 입력
python3 step03_controlstmt/inputex/inputTest4.py # ← 반지름 입력
python3 step03_controlstmt/inputex/argvEx.py 10 20 30 # ← 인자 3개 필수argvEx.py 를 인자 없이 실행하면 IndexError 가 납니다. 버그가 아니라 인자를 요구하는 프로그램입니다.
이 파일은 특이합니다. 수업이 진행된 순서가 주석으로 층층이 쌓여 있고, 파일 끝의 번호(1, 2, 3, 4)가 그 순서입니다.
파일 맨 아래 ─ 1. if 문 (가장 단순)
─ 2. if~else
─ 3. if~elif~else
파일 맨 위 ─ 4. 단순 if 나열 + 3항 연산자 (활성 상태)
아래에서 위로 읽으면 조건문이 어떻게 발전하는지 보입니다.
특히 3번과 4번을 비교해 보세요. 같은 학점 판정을 두 방식으로 짰습니다.
# 4번 (현재 활성) — if 를 5개 나열. 조건이 겹치지 않게 직접 관리해야 한다
if 90 <= score <= 100: grade = 'A'
if score >= 80 and score < 90: grade = 'B'
...
# 3번 (주석) — elif 는 앞 조건이 거짓일 때만 검사한다
if score >= 90: grade = 'A'
elif score >= 80: grade = 'B'
...elif 쪽이 짧고 안전합니다. if 를 나열하면 조건 하나만 잘못 써도 여러 개가 동시에 참이 되어 마지막 것이 이깁니다.
4번의
90 <= score <= 100은 파이썬 고유 문법입니다. 대부분의 언어에서는score >= 90 and score <= 100이라고 써야 합니다.
print('합격') if score >= 60 else print('불합격')값_참 if 조건 else 값_거짓 순서입니다. 조건이 가운데 온다는 점이 다른 언어(조건 ? 참 : 거짓)와 달라 처음엔 어색합니다.
def switch(x):
return {
'one': 1,
'two': 2,
'three': 3
}.get(x, 9) # 없는 키면 9 (default 역할)dict 를 만들고 .get(키, 기본값) 으로 꺼내는 방식입니다. .get() 은 키가 없어도 에러 대신 기본값을 돌려주기 때문에 이게 가능합니다. (dict[키] 로 꺼내면 KeyError 가 납니다.)
이 방식에는 함정이 있습니다. 값 자리에 함수 호출을 넣으면 매번 전부 실행됩니다.
test/class_ex_01.py가 정확히 이 함정에 빠져 있으니test/README.md를 보세요.
randomEx.py 는 random 모듈의 주요 함수를 한 번에 보여 줍니다.
| 함수 | 범위 |
|---|---|
random() |
0.0 이상 1.0 미만 실수 |
uniform(1.0, 3.14) |
1.0 이상 3.14 미만 실수 |
randint(1, 100) |
1 이상 100 이하 정수 — 끝값 포함 |
randrange(1, 100, 3) |
1부터 100 미만, 3씩 건너뛰며 |
choice([...]) |
목록에서 하나 |
sample(range(1,46), 6) |
범위에서 6개, 중복 없이 (로또!) |
randint 만 끝값을 포함한다는 점을 꼭 기억하세요. 나머지는 전부 "미만"입니다.
from random import * # 모듈의 모든 함수를 이름 그대로 가져온다
from X import *는 편하지만 어떤 이름이 딸려 왔는지 알 수 없어 실무에서는 피합니다.import random후random.randint(...)로 쓰거나 필요한 것만from random import randint하는 편이 낫습니다.
import sys
x = sys.argv[0] # 프로그램 파일 이름 자신
a = int(sys.argv[1]) # 첫 번째 인자sys.argv[0] 이 인자가 아니라 파일 이름이라는 게 핵심입니다. 실제 인자는 [1] 부터입니다. 그리고 input() 과 마찬가지로 전부 문자열이라 int() 변환이 필요합니다.
고치지 않고 남겨 두었습니다. 찾아서 고치는 것이 연습 과제입니다.
if a > 0:
print(a, '는 양수입니다')
elif a <= 0:
print(a, '는 음수입니다')
else:
print(a, '는 zero입니다') # ← 여기는 절대 실행되지 않는다왜 그럴까
a 가 0 이면 a > 0 은 거짓이고 a <= 0 은 참입니다. 그래서 "음수입니다"가 출력되고 else 로는 넘어가지 않습니다. 모든 숫자는 a > 0 이거나 a <= 0 둘 중 하나라서 else 에 도달할 방법이 없습니다.
문제 지문은 a>0 a<0 a==0 세 갈래를 요구했습니다. 두 번째를 elif a < 0 으로 고쳐야 합니다.
바로 위쪽에도 비슷한 문제가 있습니다.
if a >= 50: print(a, '는 50보다 크다')
if a <= 50: print(a, '는 50보다 작다')a 가 정확히 50 이면 둘 다 출력됩니다. "50보다 크다"와 "50보다 작다"가 동시에 나오죠.
같은 합격 판정을 두 가지 방식으로 짜 놓았습니다. 그런데 평균이 정확히 60일 때 결과가 엇갈립니다.
# 방식 1
if avg >= 60: # 60 → 이쪽 (합격 계열)
...
else:
print('불합격')
# 방식 2
if avg <= 60: # 60 → 이쪽 (불합격)
print('불합격')
else:
...avg 가 60 일 때 방식 1은 합격/과락 판정으로 가고, 방식 2는 불합격이라고 합니다. 실행해서 직접 확인해 보세요 — 국어 60, 영어 60, 수학 60을 넣으면 됩니다.
어느 쪽이 맞을까
문제 지문은 "평균이 60점이상인 경우 합격"이라고 했습니다. 그러니 avg >= 60 이 맞고, 방식 2의 avg <= 60 은 avg < 60 이어야 합니다.
경계값(>= 인가 > 인가)은 조건문에서 가장 흔한 버그 원인입니다. 조건을 쓸 때마다 "딱 그 값일 때는 어디로 가는가"를 확인하는 습관을 들이세요.
Python 3.10 부터 match 문이 생겼습니다. dict 로 흉내 낼 필요가 없어졌습니다.
# 이 챕터 (dict 흉내)
def switch(x):
return {'one': 1, 'two': 2, 'three': 3}.get(x, 9)
# 지금 (match)
def switch(x):
match x:
case 'one': return 1
case 'two': return 2
case 'three': return 3
case _: return 9 # _ 가 defaultmatch 는 값 비교뿐 아니라 자료구조 분해까지 되어 dict.get() 보다 훨씬 강력합니다. 다만 dict 방식도 여전히 유효합니다 — 특히 분기가 단순한 값 대응일 때는 더 짧습니다.
그 밖에:
from random import *대신import random을 씁니다.- 명령행 인자가 많아지면
sys.argv대신 표준 라이브러리argparse를 씁니다. 도움말과 타입 검사를 알아서 해 줍니다. - 출력은 f-string이 편합니다 —
print(f'{a} 는 양수입니다').
ifEx3.py의 도달 불가else를 고치고,a = 0으로 바꿔 "zero입니다"가 나오는지 확인하세요.ifEx3.py위쪽의>= 50/<= 50도a = 50일 때 하나만 나오도록 고치세요.ifEx4.py의 두 방식이 평균 60에서 같은 답을 내도록 고치세요. 세 과목에 60을 넣어 확인하세요.ifEx1.py의 활성 코드(단순if5개 나열)를if~elif~else로 바꾸세요. 몇 줄이 줄어드나요?switchEx.py를match문으로 다시 쓰세요.randomEx.py의sample(range(1,46), 6)을 이용해 로또 번호를 정렬해서 출력하세요.argvEx.py를 인자 개수와 무관하게 동작하도록 고치세요. 인자가 없으면 안내 메시지를 내고, 있으면 전부 더하도록.