Phase 1 마지막 주제인 예외 처리(try/except) 학습. Java의 try/catch와 비교하면서 Python만의 차이점을 익히고, 빈칸/디버깅/함수 작성 문제로 확인.
| Java | Python | 설명 |
|---|---|---|
try { } | try: | 예외가 발생할 수 있는 코드 |
catch (Exception e) | except Exception as e: | 예외 잡기 |
finally { } | finally: | 항상 실행 |
throw new Exception() | raise Exception() | 예외 던지기 |
| (없음) | else: | 예외가 안 났을 때만 실행 |
Java와 거의 동일한 구조인데, Python만의 else 블록이 추가된 것이 특징이다.
try:
result = 10 / 2
except ZeroDivisionError:
print("0으로 나눌 수 없음")
else:
print(f"결과: {result}") # 예외 안 났을 때만 실행
finally:
print("항상 실행")
핵심 실행 순서:
except → finallyelse → finallyfinally는 무조건 실행 (return이 있어도!)| 예외 | 발생 상황 |
|---|---|
ZeroDivisionError | 0으로 나눌 때 |
ValueError | int("abc") 같은 잘못된 변환 |
IndexError | 리스트 범위 초과 |
KeyError | 딕셔너리에 없는 키 |
TypeError | "3" + 5 같은 타입 불일치 |
int() 함수를 예로 들면:
| 코드 | 에러 | 이유 |
|---|---|---|
int("abc") | ValueError | str→int 변환 지원하지만 값이 잘못됨 |
int(None) | TypeError | None은 int 변환 대상이 아닌 타입 |
수업 중 질문: "int(None)과 int("abc")의 차이를 잘 모르겠어. 왜 각각 다른 에러가 나는 거지?"
→ 함수가 해당 타입을 받을 수 있느냐의 문제.int()는 문자열을 받을 수 있지만(변환 지원) 값이 이상하면 ValueError, 애초에 받을 수 없는 타입이면 TypeError. 이 구분은sum += "없음"이 TypeError인 이유와도 연결된다 — int와 str의+연산 자체가 지원되지 않는 타입 문제이므로.
def convert(value):
try:
num = int(value)
except ValueError:
return "변환 실패"
else:
return num * 2
finally:
print("처리 완료")
result = convert("abc")
print(result)
출력:
처리 완료
변환 실패
except에서 return "변환 실패"가 준비되지만, 반환되기 전에 finally가 먼저 실행된다. 이건 Java도 동일한 동작이다.
def test():
try:
return 1
except:
return 2
finally:
return 3
print(test()) # 3
try에서 return 1을 준비했지만, finally의 return 3이 이를 완전히 덮어써버린다. 그래서 실무에서는 finally에 return을 넣지 않는 것이 원칙. 하지만 COS Pro에서 함정 문제로 나올 수 있으니 알아두자.
# 개별 except
except KeyError:
continue
except TypeError:
continue
# 한 줄로 묶기
except (KeyError, TypeError):
continue
처리 로직이 같으면 괄호로 묶어서 한 번에 잡을 수 있다.
def safe_convert(items):
result = []
for item in items:
try:
num = int(item)
result.append(num)
except ValueError:
continue
return result
print(safe_convert(["10", "hello", "20", "3.5", "30"]))
# [10, 20, 30]
변환이 보장되면 [int(x) for x in items] 한 줄이면 되지만, 예외 처리가 필요하면 try/except + for문이 정석이다. try는 컴프리헨션 안에 넣을 수 없기 때문.
def safe_sum(dict_list, key):
total = 0
for d in dict_list:
try:
total += d[key]
except (KeyError, TypeError):
continue
return total
KeyError: 키가 없는 딕셔너리 건너뛰기TypeError: int + str 연산 불가능한 경우 건너뛰기수업 중 질문: "TypeError인지 ValueError인지 고민했는데, 형변환 과정이 없으니 TypeError가 맞나?"
→ 정확하다.int("없음")처럼 형변환을 시도하면 ValueError,0 + "없음"처럼 형변환 없이 바로 더하면 int+str 연산이 되어 TypeError. 이 코드에서는 형변환 없이 바로+=하니까 TypeError.
# 위험한 코드
sum = 0 # 내장함수 sum()을 덮어씀
dict = {"a": 1} # 내장타입 dict를 덮어씀
# 안전한 코드
total = 0
d = {"a": 1}
Python은 내장함수/타입도 변수처럼 재할당할 수 있어서, 실수로 덮어쓰면 이후 sum(), dict()를 사용할 수 없게 된다.