PYTHON

파이썬 if 조건문 — 아홉 줄짜리 합격 판정기에 숨은 실수 세 개(=, 들여쓰기, elif 순서)

PANCO_IT
#파이썬#python#if문#조건문#elif#else#들여쓰기#IndentationError#비교연산자#파이썬기초#파이썬독학

자전거 신호가 켜진 도시의 보행 신호등

이미지 출처: Pexels, cottonbro studio · Pexels License

아래 아홉 줄에는 실수가 세 개 숨어 있습니다. 점수를 입력받아 만점, 우수 합격, 합격, 불합격 중 하나를 찍어 주는 코드인데, 지금 이대로는 첫 실행에서 멈춥니다. 고치면 다음 실수에서 또 멈추고, 그것까지 고치면 이번엔 멈추지 않고 틀린 답을 냅니다.

score = int(input("점수: "))
if score = 100:
    print("만점입니다")
elif score >= 60:
    print("합격입니다")
elif score >= 90:
    print("우수 합격입니다")
else:
print("불합격입니다")

지난 편 끝에 "0으로 나누기 전에 멈추는 법"을 예고했습니다. 그 도구가 if입니다. 조건이 참이면 아래 블록을 실행하고, 거짓이면 건너뜁니다. 신호등과 같습니다. 초록이면 건너고, 빨강이면 멈추고, 그 사이에 노랑이 있습니다. if가 초록, elif가 노랑, else가 "그 외 전부"인 빨강입니다. 문법은 이게 다인데 실수는 정해진 자리에서 납니다. 위 코드에서 셋을 차례로 찾아보겠습니다.

실수 1 — 등호 하나는 "넣기", 둘은 "같은가 묻기"

두 번째 줄 if score = 100:을 실행하면 파이썬이 이렇게 답합니다.

SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?

3편에서 =는 "같다"가 아니라 "오른쪽 값을 왼쪽 상자에 넣는다"라고 했습니다. score = 100은 점수를 100으로 바꿔 버리는 명령이지 질문이 아닙니다. 조건 자리에는 질문이 와야 하니 파이썬이 "혹시 ==를 쓰려던 것 아니냐"고 묻는 것입니다. 파이썬 3.10부터는 이렇게 힌트까지 붙여 줍니다.

같은가 묻는 기호는 ==입니다. 비교 연산자는 여섯 개이고, 결과는 전부 True 아니면 False입니다.

비교 연산자 여섯 개 — 답은 True 아니면 False
print(3 == 3, 3 != 4)       # 같다, 다르다
print(5 > 3, 5 < 3)         # 크다, 작다
print(5 >= 5, 4 <= 3)       # 크거나 같다, 작거나 같다
print("a" == "A")           # False — 대소문자를 가립니다
age = 20
print(age >= 19 and age < 65)   # 둘 다 참이어야 True
print(19 <= age < 65)           # 같은 뜻, 파이썬은 이렇게 이어 쓸 수 있습니다

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

마지막 두 줄이 조건을 잇는 방법입니다. and는 둘 다 참일 때, or는 하나만 참이어도, not은 뒤집습니다. 그리고 파이썬은 19 <= age < 65처럼 수학 시간 표기를 그대로 받아 줍니다. 다른 언어에서는 안 되는 문법이라 자바를 먼저 배운 분이 오히려 놀라는 자리입니다.

첫 실수를 고치면 두 번째 줄은 if score == 100:입니다. 그런데 이 줄에는 함정이 하나 더 있습니다. 줄 끝의 콜론(:) 입니다. 콜론을 빼면 SyntaxError: expected ':'가 납니다. if, elif, else 줄은 전부 콜론으로 끝납니다. "이 줄 아래에 블록이 온다"는 표시입니다.

실수 2 — 마지막 줄이 else 밑으로 들어가지 않았습니다

==로 고치고 다시 실행하면 이번엔 아홉 번째 줄에서 멈춥니다.

IndentationError: expected an indented block after 'else' statement on line 8

"8번째 줄의 else 뒤에 들여쓴 블록이 와야 하는데 없다"는 뜻입니다. 자바나 C는 { }로 블록을 표시하지만 파이썬은 중괄호가 없습니다. 대신 들여쓰기 자체가 문법입니다. 콜론 다음 줄부터 네 칸 들여쓴 줄들이 그 조건에 속하는 블록이고, 들여쓰기가 원래 자리로 돌아오면 블록이 끝난 것입니다.

if 블록·else 블록·블록 밖 세 구간을 네 칸 들여쓰기로 구분한 코드와 각 구간의 실행 조건을 나란히 표시한 그림

네 칸이 문법입니다. 같은 깊이로 들여쓴 줄들이 한 덩어리고, 들여쓰기가 없는 줄은 조건과 상관없이 항상 실행됩니다.

그래서 마지막 print("불합격입니다")else: 아래에서 네 칸 들어가야 합니다. 들여쓰기는 스페이스 네 칸이 표준입니다. 두 칸도 동작은 하지만 한 파일 안에서는 반드시 같은 칸 수를 써야 하고, 탭과 스페이스를 섞으면 눈에는 똑같아 보여도 TabError: inconsistent use of tabs and spaces in indentation으로 멈춥니다. 에디터 대부분은 탭 키를 누르면 스페이스 네 칸을 넣어 주니 그 설정을 켜 두면 됩니다.

들여쓰기 에러는 한 가지가 더 있습니다. 블록 안의 줄들 사이에서 칸 수가 어긋나면 IndentationError: unindent does not match any outer indentation level이 납니다. 네 칸 밑에 두 칸짜리 줄이 오는 경우입니다. 붙여 넣기 하다가 자주 생기는데, 메시지에 줄 번호가 있으니 그 줄의 앞 공백을 지우고 다시 네 칸 넣으면 끝입니다.

실수 3 — 95점을 넣었는데 "합격입니다"만 나옵니다

두 실수를 고치면 프로그램이 돕니다. 그런데 95를 넣어 보면 "우수 합격입니다"가 아니라 "합격입니다"가 찍힙니다. 에러 메시지가 없어서 이 실수가 셋 중 가장 위험합니다.

돌아가지만 답이 틀립니다 — 95점을 넣어 보세요
score = int(input("점수: "))
if score == 100:
  print("만점입니다")
elif score >= 60:
  print("합격입니다")
elif score >= 90:
  print("우수 합격입니다")
else:
  print("불합격입니다")

이 예제는 키보드 입력을 씁니다. 실행창 아래 STDIN 칸에 미리 넣어 둔 값(95)을 바꿔 가며 실행해 보세요.

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

원인은 검사 순서입니다. if, elif, elif, else위에서부터 차례로 검사하고, 처음 참이 되는 곳에서 그 블록만 실행한 뒤 전체를 빠져나갑니다. 95는 score >= 60에서 이미 참이 되어 "합격입니다"를 찍고 끝납니다. 그 아래 score >= 90은 검사조차 되지 않습니다. 이 코드에서 "우수 합격입니다"는 어떤 점수를 넣어도 절대 나올 수 없는 문장입니다.

같은 95점을 넓은 조건이 먼저인 코드와 좁은 조건이 먼저인 코드에 넣었을 때 각각 합격입니다와 우수 합격입니다로 결과가 갈리는 과정을 두 칸으로 비교한 그림

조건은 위에서부터 검사하고 처음 참인 칸에서 멈춥니다. 넓은 조건(60 이상)이 위에 있으면 좁은 조건(90 이상)은 영원히 차례가 오지 않습니다.

고치는 규칙은 하나입니다. 좁은 조건을 위에, 넓은 조건을 아래에. 100은 90 이상에도 포함되고 90 이상은 60 이상에도 포함되니, == 100>= 90>= 60 → 나머지 순서가 됩니다. 이렇게 두면 각 elif는 "위 조건에는 안 걸렸고"라는 뜻을 자동으로 품게 됩니다. elif score >= 60:은 사실 "90 미만이면서 60 이상"입니다. 그래서 60 <= score < 90이라고 길게 쓸 필요가 없습니다.

고친 코드 전문

세 실수를 모두 고친 코드입니다. 마지막에 들여쓰기 없는 print("판정 끝")을 한 줄 붙였습니다. 어느 갈래로 가든 이 줄은 항상 실행됩니다.

고친 판정기 — STDIN의 95를 100, 60, 59로 바꿔 보세요
score = int(input("점수: "))
if score == 100:
  print("만점입니다")
elif score >= 90:
  print("우수 합격입니다")
elif score >= 60:
  print("합격입니다")
else:
  print("불합격입니다")
print("판정 끝")

이 예제는 키보드 입력을 씁니다. 실행창 아래 STDIN 칸에 미리 넣어 둔 값(95)을 바꿔 가며 실행해 보세요.

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

95는 "우수 합격입니다", 100은 "만점입니다", 60은 "합격입니다", 59는 "불합격입니다"가 나오고, 넷 다 그 아래에 "판정 끝"이 붙습니다. 경계값인 60과 59, 90과 89를 넣어 보는 습관을 들이면 순서 실수는 대부분 잡힙니다. 조건문 검사는 항상 경계 바로 위와 바로 아래에서 합니다.

elifelse는 있어도 되고 없어도 됩니다. if 하나만 써도 되고, if + else만 써도 됩니다. elif는 필요한 만큼 몇 개든 이어 붙일 수 있고, else는 맨 마지막에 한 번만 옵니다.

지난 편의 숙제 — 0으로 나누기 전에 멈추기

5편에서 7 / 0, 7 // 0, 7 % 0이 전부 ZeroDivisionError로 멈춘다고 했습니다. 입력값으로 나누는 프로그램은 0이 들어올 수 있으니, 나누기 전에 if로 한 번 묻습니다.

나누는 수가 0이면 나누지 않습니다 — STDIN 둘째 줄을 2로 바꿔 보세요
a = int(input("나눌 수: "))
b = int(input("나누는 수: "))
if b == 0:
  print("0으로는 나눌 수 없습니다")
else:
  print(a / b, a // b, a % b)

이 예제는 키보드 입력을 씁니다. 실행창 아래 STDIN 칸에 미리 넣어 둔 값(7 ⏎ 0)을 바꿔 가며 실행해 보세요.

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

70을 넣으면 "0으로는 나눌 수 없습니다", 72를 넣으면 3.5 3 1이 나옵니다. 에러로 멈추는 대신 프로그램이 상황을 설명하고 계속 갑니다. 이것이 조건문이 하는 일의 절반입니다. 나머지 절반은 "값에 따라 다른 일을 시키는 것"이고, 그 예가 위의 판정기입니다.

한 가지만 덧붙이면, if b == 0: 대신 if not b:라고 쓴 코드를 종종 봅니다. 파이썬은 0, 빈 문자열 "", 빈 리스트 []를 조건 자리에서 거짓으로 취급하고 나머지는 참으로 봅니다. 그래서 if b:는 "b가 0이 아니면"과 같습니다. 편리하지만 "0"처럼 문자열로 된 0은 비어 있지 않아서 참이 되니, 숫자를 다룰 때는 == 0으로 분명하게 쓰는 편이 초보 단계에서는 안전합니다.

세 실수, 세 증상

실수증상언제 드러나나고치는 법
if score = 100:SyntaxError ... Maybe you meant '=='실행 즉시같은지 물을 때는 ==, 콜론 확인
else: 아래 들여쓰기 없음IndentationError: expected an indented block실행 즉시콜론 다음 줄부터 스페이스 네 칸
넓은 조건이 위에에러 없음, 특정 답만 절대 안 나옴경계값을 넣어 봐야좁은 조건을 위로, 경계값 테스트

앞의 둘은 파이썬이 줄 번호까지 짚어 주니 메시지를 읽으면 끝납니다. 세 번째는 아무도 알려 주지 않습니다. 그래서 조건문을 쓰면 반드시 경계값을 한 번씩 넣어 보는 것이고, 이 습관이 다음 편 반복문에서도 그대로 이어집니다.

실수 감별 — 아래 문항의 코드에서 무엇이 잘못됐는지

미니 퀴즈

OX 3문제 + 4지선다 3문제


포켓코딩(PYTHON1) 6편 · 5편(파이썬 연산자)에서 이어집니다. 예제 코드는 강사 개인 GitHub 저장소의 연습 문제를 바탕으로 다시 썼습니다. 다음 편: 파이썬 리스트 — 여러 값을 한 줄로 세우고, 0번부터 세는 이유.

PANCO_IT

IT 지식을 정리하는 개발자

관련 글