본문 바로가기
C.W.K.
Stream
Lesson 01 of 05 · published

EAFP와 덕 타이핑 — 능력을 믿고 실패를 다루기

~18 min · eafp, duck-typing, idiom, trust

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

LBYL은 실행 전에 조건을 확인하고, EAFP는 먼저 시도한 뒤 예상한 실패를 잡아. Python은 성공 흐름이 또렷하고 검사와 실행 사이의 경쟁 조건을 줄이는 EAFP를 자주 택해. 그렇다고 모든 예외를 삼키라는 뜻은 아니야. 회복할 수 있는 좁은 예외만 처리해.

덕 타이핑은 정확한 클래스 이름보다 필요한 동작을 봐. 반복 가능한 값을 받는 함수가 리스트인지 확인하면 튜플·집합·제너레이터를 괜히 거부해. 직접 순회하거나 Protocol·Iterable 같은 계약으로 필요한 능력을 표현해.

isinstance가 나쁜 것도 아니야. 직렬화처럼 타입마다 형식이 정말 달라지거나 보안 경계를 검증해야 하면 맞는 도구야. 바깥 경계에서 값과 모양을 확인한 뒤에는 세워진 내부 계약을 믿어. 구현 클래스를 습관적으로 제한하지 말고 실제로 필요한 능력만 묻는 게 핵심이야.

Code

미리 검사하지 않고 시도하기·python
# LBYL — 방어적, 장황, race condition 있음
def get_field_lbyl(obj, name):
    if hasattr(obj, name):
        attr = getattr(obj, name)
        if callable(attr):
            return attr()
        return attr
    return None

# EAFP — 시도, fallback
def get_field_eafp(obj, name):
    try:
        attr = getattr(obj, name)
        return attr() if callable(attr) else attr
    except AttributeError:
        return None

# 둘 다 작동, EAFP 가 짧고 Python 문화에 매치
반복 가능한 값을 받는 덕 타이핑·python
# UNPYTHONIC — 좁은 타입 체크
def sum_strict(xs):
    if not isinstance(xs, list):
        raise TypeError("list 필요")
    total = 0
    for x in xs:
        total += x
    return total

# PYTHONIC — 어떤 iterable 도 받음
def sum_pythonic(xs):
    total = 0
    for x in xs:           # list, tuple, generator, set, ... 작동
        total += x
    return total

print(sum_pythonic([1, 2, 3]))
print(sum_pythonic((1, 2, 3)))
print(sum_pythonic(x*x for x in range(4)))
print(sum_pythonic({1, 2, 3}))
타입 힌트로 필요한 능력 적기·python
from typing import Iterable

def sum_typed(xs: Iterable[int]) -> int:
    """타입 힌트가 'int 의 iterable', 런타임은 duck-typed."""
    return sum(xs)

# 타입 체커 (mypy) 가 caller 가 iterable 넘기는지 검증.
# 런타임이 isinstance 검사를 하지 않고 — 그냥 반복.
# 둘 세계의 best — 정적 계약, 런타임 유연성.
isinstance가 맞는 경계·python
# 시스템 경계에서 — 신뢰할 수 없는 데이터 검증:
def parse_user_input(data):
    if not isinstance(data, dict):
        raise TypeError("API 에서 dict 기대")
    # ... 데이터 처리

# 진짜 타입에 dispatch 필요할 때:
def format_value(x):
    if isinstance(x, (int, float)):
        return f"{x:.2f}"
    if isinstance(x, str):
        return f'"{x}"'
    return repr(x)
# (singledispatch 가 여기서 더 깔끔 — oop-advanced 트랙)

# 유효 사용. 안티패턴은 타입 힌트로 계약이 이미 명확한 함수 안의
# isinstance 방어성.

External links

Exercise

리스트인지 먼저 검사하는 first_positive(items)를 EAFP 흐름으로 다시 쓰고 Iterable[int] 힌트를 붙여. 튜플·제너레이터·집합도 작동하지만 원래 LBYL 버전은 거부한다는 걸 보여줘.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.