TypeError와 ValueError 중 무엇이 떴는지로 원인을 반씩 좁히는 법
문제 발생
비슷해 보이는 두 오류가 다른 원인이었는데 처음에는 구분 없이 "입력이 이상하다"로만 읽고 있었습니다.
int("12a") # ValueError: invalid literal for int() with base 10: '12a'
int(["12"]) # TypeError: int() argument must be a string, a bytes-like object or a real number, not 'list'
"3" + 3 # TypeError: can only concatenate str (not "int") to str원인 분석
파이썬 문서가 두 예외의 경계를 명확히 정합니다.
TypeError— "부적절한 타입의 객체에 연산이나 함수가 적용될 때" 발생합니다.ValueError— "타입은 맞지만 값이 부적절한 인자를 받았고,IndexError같은 더 구체적인 예외로 설명되지 않을 때" 발생합니다.
문서의 요약이 그대로 기준입니다 — 잘못된 타입의 인자는 TypeError, 잘못된 값의 인자는 ValueError.
그래서 예외 이름만으로 수사 범위가 갈립니다.
| 예외 | 의심할 곳 |
|---|---|
TypeError | 값이 어디서 왔는가. 타입이 다르다는 건 대개 잘못된 변수를 넘겼거나 변환을 빠뜨린 것 |
ValueError | 값 자체가 무엇인가. 형식·범위 검증이 빠진 자리 |
해결 방안
- 메시지의 뒷부분을 봅니다.
TypeError는 기대한 타입과 실제 타입을 함께 알려 줍니다(... not 'list').ValueError는 문제가 된 값을 그대로 보여 줍니다('12a'). - 경계에서 검증하고 알맞은 예외를 던집니다. 라이브러리를 만들 때 이 구분을 지키면 쓰는 쪽이 같은 방식으로 진단할 수 있습니다.
def set_age(value):
if not isinstance(value, int):
raise TypeError(f"age는 int여야 합니다: {type(value).__name__}")
if value < 0:
raise ValueError(f"age는 0 이상이어야 합니다: {value}")except를 뭉뚱그리지 않습니다. 두 예외를 한 번에 잡으면 위 정보가 사라집니다. 처리 방법이 다르면 따로 잡습니다.
try:
quantity = int(raw)
except ValueError:
return "숫자를 입력해 주세요" # 사용자 입력 문제
except TypeError:
raise # 우리 코드의 버그 — 감추지 않는다- 지원할 생각이 있는 연산인데 아직 구현하지 않았다면
NotImplementedError를 씁니다. 문서가 권하는 구분입니다 —TypeError는 "지원하지 않는 연산",NotImplementedError는 "지원할 예정이지만 아직 없음"입니다. - 원인 예외를 잃지 않습니다. 다시 던질 때
raise ... from e로 연결해 두면 로그에 원래 오류가 함께 남습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.