← SEARCHABLE ARCHIVE
Python · 2026-07-25

Python 기초부터 마스터까지 — 4화

함수, 타입 힌트, 예외로 코드의 계약 표현하기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

함수는 코드를 줄이는 도구를 넘어 입력, 출력, 실패 조건을 이름으로 표현하는 작은 계약이다. 함수의 책임이 분명하면 테스트와 재사용도 쉬워진다.

함수의 계약 만들기

def parse_level(raw: str, *, maximum: int = 100) -> int:
    """문자열을 1부터 maximum 사이의 레벨로 변환한다."""
    level = int(raw)
    if not 1 <= level <= maximum:
        raise ValueError(f"레벨은 1부터 {maximum} 사이여야 합니다.")
    return level

raw: str과 -> int는 타입 힌트다. maximum 앞의 *는 호출할 때 maximum=50처럼 이름을 적게 만들어 인자의 의미를 분명하게 한다.

타입 힌트는 실행 중 값을 자동으로 검사하지 않는다. 편집기와 정적 분석 도구가 오류를 일찍 찾도록 돕지만 명령줄, JSON, 파일처럼 외부에서 들어온 값은 실행 시점에도 검증해야 한다.

변경 가능한 기본 인자 피하기

def add_item(item: str, items: list[str] = []) -> list[str]:
    items.append(item)
    return items

기본 인자는 함수를 호출할 때마다 새로 만들어지지 않고 함수가 정의될 때 한 번 만들어진다. 위 리스트는 여러 호출이 공유한다.

def add_item(item: str, items: list[str] | None = None) -> list[str]:
    result = [] if items is None else items.copy()
    result.append(item)
    return result

입력 리스트를 직접 바꿀지 복사할지도 함수의 계약이다. 위 함수는 호출자가 가진 리스트를 보호하기 위해 복사본을 반환한다.

예외에 의미 붙이기

class ConfigError(ValueError):
    pass


def parse_timeout(raw: str) -> float:
    try:
        seconds = float(raw)
    except ValueError as error:
        raise ConfigError("timeout은 숫자여야 합니다.") from error

    if not 0 < seconds <= 30:
        raise ConfigError("timeout은 0초 초과 30초 이하여야 합니다.")
    return seconds

raise ... from error는 사용자가 이해할 오류와 원래 원인을 함께 보존한다. 모든 예외를 except Exception 하나로 잡으면 프로그래밍 오류와 복구 가능한 입력 오류를 구분하기 어렵다.

입력과 계산 분리하기

def format_result(success: int, failed: int) -> str:
    total = success + failed
    if total == 0:
        return "처리 결과가 없습니다."
    return f"성공률: {success / total * 100:.1f}%"


def main() -> None:
    success = int(input("성공 수: "))
    failed = int(input("실패 수: "))
    print(format_result(success, failed))

키보드 입력과 화면 출력을 main에 두고 계산을 별도 함수로 분리하면 여러 입력을 빠르게 검증할 수 있다. 시간, 난수, 파일, 네트워크도 같은 방식으로 프로그램의 핵심 규칙과 분리할 수 있다.

좋은 함수는 짧기만 한 함수가 아니다. 이름과 매개변수만 읽어도 무엇을 계산하고 어떤 상태를 바꾸며 언제 실패하는지 예상할 수 있어야 한다.