Devin.KR

값과 조건 읽기

80분 안팎

학습 목표

Python으로 제목 정규화와 길이 검사를 구현하고 경계 입력을 채점합니다.

개념

값을 알아야 조건의 뜻이 보입니다

AI가 작성한 코드가 짧아도 입력값이 어느 조건을 통과하는지 설명하지 못하면 변경을 승인하기 어렵습니다. 신입에게 먼저 부탁하는 일은 문법 이름을 외우는 일이 아니라 사례 하나를 골라 각 줄에서 값이 무엇인지 적는 일입니다. 앞 모듈의 C02는 앞뒤 공백이 있는 제목을 정리하고 C03은 공백만 있는 제목을 거절합니다. 두 입력을 같은 경로라고 생각하면 빈 제목을 생성하는 결함을 놓칩니다.

이번 레슨은 앞 모듈에서 만든 판정 함수를 다시 쓰되 원본 값, 정리한 값, 길이를 구분해서 읽습니다. 명세는 문자열인 제목의 앞뒤 공백을 제거한 뒤 길이를 검사합니다. 유효한 길이는 Python len 기준 1~40 코드 포인트입니다. 화면에서 하나로 보이는 결합 문자나 이모지가 여러 코드 포인트일 수 있으므로 화면상 글자 수와 같다고 설명하지 않습니다. 여기서는 Unicode 정규화나 바이트 제한을 추가하지 않습니다.

Python 값에는 자료형이 있습니다. 따옴표로 감싼 “12”는 문자열이고 12는 정수입니다. True와 False는 참과 거짓을 나타내며 None은 값이 없음을 표현합니다. JSON을 읽으면 문자열은 str, 숫자 12는 int, null은 None, true는 True로 해석됩니다. 외부 입력을 모두 문자열이라고 가정하면 JSON 숫자 제목을 잘못 허용할 수 있습니다. 이번 입력은 JSON 객체이며 title 누락도 형식 오류로 다룹니다.

변수는 값에 붙이는 이름입니다. title에 들어온 문자열에 strip을 호출하여 clean에 연결하면 앞뒤 공백이 빠진 문자열을 얻습니다. title 자체를 수정하는 명령은 아닙니다. 길이 검사는 clean을 대상으로 수행합니다. 원본 길이가 44여도 앞뒤 공백을 뺀 길이가 40이면 허용합니다. 내부의 연속 공백은 보존합니다. split과 join으로 모든 공백을 하나로 합치면 다른 정규화 규칙을 몰래 넣는 셈입니다.

조건을 읽는 순서가 결과를 결정합니다

if는 조건이 참일 때 들여쓴 블록을 실행합니다. 콜론과 들여쓰기는 블록 경계를 표시합니다. isinstance(title, str)가 거짓이면 문자열 메서드를 호출하지 않고 INVALID_TITLE_TYPE을 반환합니다. 숫자나 None에 strip을 먼저 호출하면 예상한 실패 결과 대신 AttributeError가 납니다. 에러를 나중에 잡는 것보다 명세의 형식 확인 순서를 코드에서 드러내는 편이 이번 판정 함수를 읽기 쉽습니다.

clean이 빈 문자열이면 EMPTY_TITLE을 반환합니다. 공백 하나는 원본에서는 비어 있지 않지만 strip 뒤에는 비어 있습니다. if title만으로 검사하면 공백만 있는 제목도 참으로 판단됩니다. 참·거짓 판정은 편리하지만 계약이 정규화된 빈 값인지 묻는 자리에서는 clean == 빈 문자열로 비교 대상을 분명히 합니다. None과 숫자 0을 빈 제목으로 합치지 않습니다.

길이 상한은 len(clean) > 40일 때 거절합니다. >= 40으로 쓰면 허용 경계인 40자도 거절합니다. 1자, 40자, 41자를 나란히 실행해 보면 연산자 하나가 결과를 어떻게 바꾸는지 보입니다. 짧은 정상 제목만 넣어 본 실행은 이 경계를 확인하지 못합니다. 조건을 읽을 때 거절 구간과 허용 구간을 각각 말해 보고 둘 사이에 빠지거나 겹친 값이 없는지 확인합니다.

return은 해당 함수 호출을 끝내고 값을 호출자에게 돌려줍니다. 형식 오류에서 return하면 공백 제거와 길이 검사는 실행되지 않습니다. 마지막 성공 반환에는 ok, title, length를 넣습니다. length는 이 레슨에서 값 추적을 위해 추가한 출력이고 프로젝트의 생성 API 계약에 추가하는 필드가 아닙니다. 학습용 관찰 값과 실제 계약을 구분해서 후속 구현에 옮깁니다.

손으로 추적하고 실행으로 대조합니다

종이에 title, type, clean, length, 선택한 분기를 열로 적습니다. 숫자 제목은 clean과 length 칸에 “실행되지 않음”을 씁니다. 공백 제목은 clean이 빈 문자열이고 길이 상한 검사 전에 반환한다고 적습니다. 40자 제목은 성공 분기까지 도달합니다. 아직 계산하지 않은 값을 추측해서 표에 채우지 않는 습관이 디버깅에서 중요합니다.

따라하기 코드는 각 단계가 독립 실행되도록 작성되어 있습니다. Python 실행 창에 코드 블록 전체를 복사하거나 main.py에 저장해 python3 main.py로 실행합니다. 다른 단계의 변수에 의존하지 않습니다. 브라우저 실습은 표준 입력 JSON 한 개를 받고 표준 출력 JSON 한 개를 냅니다. 설명 문구나 임시 print를 출력에 더하면 정답 결과가 있어도 채점 출력이 달라집니다.

실습 starter는 유효 여부를 제대로 검사하지 않습니다. validate_title의 조건과 반환값을 수정하고 입력을 읽는 두 줄은 유지합니다. solution을 보기 전에 각 테스트가 형식, 공백, 하한, 상한 중 어떤 규칙을 확인하는지 적습니다. 예제 입력을 비교해서 문자열 전체가 특정 값일 때만 통과시키는 코드는 새로운 제목에 적용할 수 없으므로 일반 규칙으로 구현합니다.

흔한 오류인 NameError는 clean을 만들기 전에 사용했거나 이름을 다르게 썼다는 신호입니다. AttributeError에 strip이 보이면 실패 입력의 자료형과 형식 검사 위치를 봅니다. IndentationError는 if와 return의 들여쓰기를 확인합니다. 오류 메시지의 마지막 줄에서 종류와 설명을 읽고 그 위에서 자신이 작성한 줄을 찾습니다. 오류를 없애기 위해 숫자를 str로 바꾸면 명세 위반이 남습니다.

JSONDecodeError는 제목 검증까지 도달하기 전 입력 문법에서 실패한 것입니다. 작은따옴표나 Python의 True를 JSON에 쓰지 않았는지 확인합니다. 입력에는 큰따옴표와 true, false, null을 사용합니다. 검증기는 정상 JSON 객체를 제공하므로 이번 함수가 깨진 JSON을 복구할 필요는 없습니다. 실패 위치를 입력 해석과 업무 판정으로 분리해서 설명합니다.

레슨을 마치면 처음 보는 제목에 대해 형식 확인, 공백 제거, 빈 값, 길이 상한을 차례로 예측할 수 있어야 합니다. 특히 앞뒤 공백을 뺀 40자는 허용하고 숫자는 길이와 무관하게 거절한다는 근거를 자신의 말로 설명합니다. 변수와 자료형의 일반적인 활용은 더 읽기에 맡기고 여기서는 이 계약의 조건을 추적하는 데 집중합니다.

따라하기

형식과 정리한 값을 구분합니다

원본과 clean을 표에 적고 내부 공백이 유지되는지 확인합니다.

title = "  자료  정리  "
clean = title.strip()
print(type(title).__name__)
print(repr(title), repr(clean))
print(len(title), len(clean))

실행 결과

str
'  자료  정리  ' '자료  정리'
10 6

하한과 상한을 실행합니다

각 입력이 성공인지 먼저 예측하고 실행 결과와 비교합니다.

for raw in [" \t ", "가", "가" * 40, "가" * 41]:
    clean = raw.strip()
    print(len(clean), 1 <= len(clean) <= 40)

실행 결과

0 False
1 True
40 True
41 False

오류보다 먼저 형식을 검사합니다

문자열 메서드가 어느 입력에서 실행되지 않는지 표시합니다.

for title in [12, None, "복습"]:
    if not isinstance(title, str):
        print("INVALID_TITLE_TYPE")
    else:
        print(title.strip())

실행 결과

INVALID_TITLE_TYPE
INVALID_TITLE_TYPE
복습

브라우저 실습과 미션에 연결합니다

starter에서 지정한 함수를 수정한 뒤 정상·경계·실패 테스트를 실행합니다. 실패 입력을 손으로 추적하고 기대값 대신 구현을 고칩니다. 추적 표를 보관하고 다음 레슨의 함수 경계에서 사용합니다.

확인 문제

실습

JSON 객체의 title을 검사합니다. 문자열이 아니거나 누락이면 INVALID_TITLE_TYPE, strip 뒤 빈 값이면 EMPTY_TITLE, len(clean)이 40 초과면 TITLE_TOO_LONG을 반환합니다. 성공은 ok:true, 정리한 title, length입니다. 내부 공백은 유지합니다. validate_title을 수정하고 JSON 한 개만 출력합니다. length는 레슨 관찰값이며 프로젝트 생성 응답에는 넣지 않습니다.

모범 답안
import json
import sys


def validate_title(title):
    if not isinstance(title, str):
        return {"ok": False, "error": "INVALID_TITLE_TYPE"}
    clean = title.strip()
    if clean == "":
        return {"ok": False, "error": "EMPTY_TITLE"}
    if len(clean) > 40:
        return {"ok": False, "error": "TITLE_TOO_LONG"}
    return {"ok": True, "title": clean, "length": len(clean)}

payload = json.load(sys.stdin)
print(json.dumps(validate_title(payload.get("title")), ensure_ascii=False))

더 읽기

면접 질문

  • AI가 만든 코드가 실행될 때 추가로 확인할 내용을 설명해 주시면 됩니다.