유효한 쪽수 결정하기
75분 안팎
학습 목표
비교·논리곱·부정 조건을 경계값으로 검증합니다.
개념
왜 조건을 경계값으로 검증하는가
읽은 쪽수는 0 이상의 정수입니다. 0은 아직 읽지 않았다는 유효한 기록이며 음수는 입력 실수입니다. pages > 0을 유효 조건으로 쓰면 음수를 막는 동시에 0까지 거부합니다. 겉으로는 간단한 부호 검사지만 업무 계약을 한 글자 다르게 옮기면 실제 기록이 누락됩니다. 저는 신입이 조건식을 작성하기 전에 허용되는 값과 거부할 값을 적도록 합니다. 이번에는 제목이 비어 있지 않고 쪽수가 0 이상일 때 기록을 받아들입니다. 읽기 목표 100쪽은 레슨의 완료 분류용 기준이며 실제 책의 전체 쪽수를 뜻하지 않습니다.
말을 비교식으로 옮긴다
0 이상은 pages >= 0입니다. 음수는 pages < 0이며 100 이상은 pages >= 100입니다. 같다는 비교는 ==이고 같지 않다는 비교는 !=입니다. 양끝을 포함하는 범위는 0 <= pages <= 100처럼 연쇄 비교로 표현할 수 있습니다. 다만 이번 쪽수 계약에는 상한이 없으므로 유효성 검사를 100 이하로 제한하지 않습니다. 100쪽 목표를 넘은 101쪽도 유효하고 완료로 분류합니다. 유효 입력을 정하는 조건과 목표 달성 여부를 정하는 조건은 서로 다른 질문입니다. 이름을 valid와 completed로 나누면 각 조건의 의도를 설명하기 쉽습니다.
둘 다 필요하면 and를 쓴다
title != "" and pages >= 0은 제목과 쪽수의 두 조건이 모두 참일 때 참입니다. or로 바꾸면 둘 중 하나만 참이어도 통과합니다. 예를 들어 제목이 책이고 쪽수가 -1이면 제목 조건만 참인데 or는 이를 허용합니다. not은 조건의 참·거짓을 뒤집습니다. not valid는 검증 실패를 뜻하지만 not pages는 쪽수 0에서 참이므로 같은 뜻이 아닙니다. not (title == "" or pages < 0)은 빈 제목도 아니고 음수도 아니라는 뜻으로 두 유효 조건을 and로 묶은 것과 같습니다. 부정할 때 괄호 안의 범위를 먼저 읽습니다.
참·거짓 표로 규칙을 점검한다
제목 유효 여부와 쪽수 유효 여부가 각각 참 또는 거짓일 때 네 조합이 생깁니다. and는 두 조건이 참인 한 조합만 허용합니다. 따라하기에서 네 조합을 직접 출력해 or와 비교합니다. 이 표는 외울 논리 기호가 아니라 입력 정책을 검토하는 도구입니다. 책과 -1, 빈 제목과 0 같은 반례를 하나씩 대입해 봅니다. 조건식의 모양만 보고 맞다고 판단하지 않습니다. not으로 전체 조건을 뒤집는 식을 쓸 때도 동일한 입력 네 조합으로 확인하면 괄호를 빠뜨린 오류를 발견하기 쉽습니다.
검증 실패를 먼저 분기한다
if title == "":에서는 ERR_TITLE을 출력합니다. elif pages < 0:에서는 ERR_PAGES를 출력합니다. else:에서는 유효한 기록만 분류합니다. if/elif/else는 위에서부터 검사해 처음 참인 분기 하나를 실행합니다. 제목과 쪽수가 동시에 잘못됐을 때 제목 오류를 우선하는 규칙을 이 순서로 나타냅니다. 별개의 if를 여러 개 쓰고 마지막에 항상 OK를 출력하면 오류와 성공이 동시에 나올 수 있습니다. 정해진 오류 하나 또는 성공 하나만 출력한다는 계약을 먼저 세워야 분기 구조를 선택할 수 있습니다. 실패 시 기록 후보를 만들지 않는 흐름도 같은 이유로 필요합니다.
완료 분류는 검증 다음이다
유효한 쪽수에 대해 0이면 NOT_STARTED, 1부터 99까지는 READING, 100 이상이면 COMPLETED를 사용합니다. 먼저 pages == 0인지 묻고 다음에 pages >= 100인지 묻고 나머지를 READING으로 둡니다. 혹은 큰 값부터 검사할 수 있지만 겹치는 범위와 순서를 함께 검토해야 합니다. pages >= 0을 첫 분기로 놓으면 모든 유효 값이 거기에 들어가 완료 분기에 도달하지 않습니다. 분류는 읽기 목표 달성을 나타내는 레슨 연습입니다. 모듈 미션은 완료 상태를 저장하지 않고 제목과 쪽수의 검증 결과만 출력합니다.
문자열 비교를 피하고 숫자를 준비한다
브라우저의 쪽수 입력은 정수로 변환 가능한 문자열로 제공됩니다. int(input())으로 변환한 뒤 비교합니다. "100" >= "9" 같은 문자열 비교는 쪽수 비교가 아닙니다. 또한 pages == 0 or 1은 0 또는 1과 각각 비교하는 뜻이 아닙니다. 두 값을 비교하려면 pages == 0 or pages == 1처럼 비교를 각각 작성합니다. or 뒤에 있는 숫자 1 자체가 참으로 판정되면 조건은 예상과 다르게 동작합니다. 조건이 예상보다 넓게 참이면 and/or의 각 항이 실제 비교식인지 살핍니다. 이번 예제에서는 == 0과 >= 100을 독립된 분기로 사용합니다.
문법 오류와 잘못된 판단을 함께 찾는다
Python 조건문에서 &&는 and를 대신하지 못하고 !는 not을 대신하지 못합니다. if 줄 끝 콜론이 없거나 else 들여쓰기가 어긋나면 SyntaxError 또는 IndentationError가 나올 수 있습니다. 오류가 표시된 위치와 바로 앞 줄을 확인합니다. 반대로 or를 잘못 사용한 코드는 문법 오류 없이 잘못된 기록을 허용할 수 있습니다. 실행 종료 코드가 0이라는 사실만으로 업무 정답이라고 판단하지 않습니다. ERR_TITLE이어야 하는 입력이 OK가 되는지 테스트로 확인합니다. 오류 메시지가 없는 논리 오류는 입력과 기대 출력의 대조가 특히 중요합니다.
경계의 양쪽을 검사한다
쪽수의 유효 경계는 0이므로 -1, 0, 1을 검사합니다. 목표 경계는 100이므로 99, 100, 101을 검사합니다. 한글 제목과 공백 제목도 결합해 제목 조건을 빠뜨리지 않았는지 살핍니다. 제목과 쪽수가 모두 잘못된 입력에서 ERR_TITLE이 나오는지 확인하면 오류 우선순위도 검증할 수 있습니다. 테스트 이름에는 무엇을 보여 주는 입력인지 적습니다. 예를 들어 음수 거부와 목표 도달은 서로 다른 검사입니다. 단지 통과 개수를 늘리려 비슷한 양수만 반복하는 대신 조건식의 경계를 가르는 사례를 선택합니다.
미션에서는 숫자 문법도 계약으로 정한다
실제 명령행 입력에는 열, 1.5, 빈 문자열 같은 값이 올 수 있습니다. 미션 starter에는 숫자 변환 보조 코드가 제공됩니다. 정수 문자열은 앞뒤 공백을 제거한 뒤 선택적인 + 또는 -와 ASCII 숫자로 구성되며, 예외 처리로 변환 실패를 ERR_PAGES로 돌립니다. 이 도움 코드는 함수와 예외 문법을 아직 모르는 학습자도 그대로 사용할 수 있게 둡니다. 학습자가 작성할 부분은 제목 정리, 빈 제목 거부, 음수 거부, 성공 후보 출력입니다. 숫자 표기 정책과 숫자 크기 정책을 분리해 보면 다음 오류 레슨에서 실패 원인을 더 자세하게 설명할 수 있습니다.
조건을 수정할 때 지킬 기준
조건식을 바꾸기 전에는 기존 입력이 어느 분기로 들어가는지 적습니다. 예를 들어 완료 기준을 100에서 120으로 바꾸면 100쪽은 이제 READING이고 120쪽은 COMPLETED입니다. 이때 음수 거부나 0쪽 허용 규칙은 별도로 유지합니다. 하나의 기준 변경이 다른 검증까지 바꾸지 않도록 유효성 검사와 상태 분류를 나누어 읽습니다. 새 경계의 바로 아래, 같은 값, 바로 위를 실행하고 오류 우선순위도 확인합니다. 정상 종료만 확인하지 말고 출력의 제목·쪽수·상태가 기대한 값인지 대조합니다. 각 분기가 담당하는 입력 범위를 말로 설명할 수 있어야 조건식 수정의 영향을 검토할 수 있습니다.
따라하기
경계 조건 확인
경계값을 포함하는지 확인합니다.
print(-1 >= 0, 0 >= 0, 1 >= 0)
print(99 >= 100, 100 >= 100, 101 >= 100)
실행 결과
False True True False True True
논리 조합 비교
각 행은 제목 유효·쪽수 유효의 조합입니다. and와 or가 어떤 잘못된 입력을 허용하는지 읽습니다.
print(False and False, False or False)
print(False and True, False or True)
print(True and False, True or False)
print(True and True, True or True)
실행 결과
False False False True False True True True
유효한 0쪽 분류
제목 달빛 도서관과 쪽수 0을 두 줄로 입력합니다.
title = input().strip()
pages = int(input())
if title == "":
print("ERR_TITLE")
elif pages < 0:
print("ERR_PAGES")
else:
if pages == 0:
status = "NOT_STARTED"
elif pages >= 100:
status = "COMPLETED"
else:
status = "READING"
print(f"OK|{title}|{pages}|{status}")
실행 결과
OK|달빛 도서관|0|NOT_STARTED
오류 우선순위 실행
제목에는 공백 세 개, 쪽수에는 -1을 입력합니다. 제목 오류를 먼저 반환합니다.
title = input().strip()
pages = int(input())
if title == "":
print("ERR_TITLE")
elif pages < 0:
print("ERR_PAGES")
else:
if pages == 0:
status = "NOT_STARTED"
elif pages >= 100:
status = "COMPLETED"
else:
status = "READING"
print(f"OK|{title}|{pages}|{status}")
실행 결과
ERR_TITLE
부정 조건의 동등성
유효 조건과 무효 조건을 서로 바꾸어 확인합니다.
title = "책"
pages = -1
valid = title != "" and pages >= 0
print(valid)
print(not valid)
print(not (title == "" or pages < 0))
실행 결과
False True False
확인 문제
실습
첫 줄 제목, 둘째 줄 정수 변환 가능한 쪽수를 읽습니다. 앞뒤 공백 제거 후 빈 제목은 ERR_TITLE, 음수는 ERR_PAGES로 거부합니다. 둘 다 잘못됐으면 제목 오류만 출력합니다. 유효하면 OK|제목|쪽수|상태를 출력합니다. 상태는 0에서 NOT_STARTED, 1~99에서 READING, 100 이상에서 COMPLETED입니다. 쪽수 상한은 없습니다.
모범 답안
title = input().strip()
pages = int(input())
if title == "":
print("ERR_TITLE")
elif pages < 0:
print("ERR_PAGES")
else:
if pages == 0:
status = "NOT_STARTED"
elif pages >= 100:
status = "COMPLETED"
else:
status = "READING"
print(f"OK|{title}|{pages}|{status}")
더 읽기
면접 질문
- 제목과 쪽수가 모두 유효해야 할 때 and와 or 중 무엇을 쓰며 반례는 무엇인가요?
- 0쪽 허용과 100쪽 목표 달성을 검증할 경계값을 골라 주세요.
- 제목과 쪽수가 모두 잘못됐을 때 오류 하나만 출력하는 분기 구조를 설명해 주세요.