본문 바로가기
C.W.K.
Stream
Lesson 02 of 06 · published

EAFP와 LBYL — 확인할까, 시도할까

~15 min · eafp, lbyl, idiom, ask-forgiveness

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

두 방식은 실패의 성격을 다르게 본다

LBYL은 가능 여부를 먼저 확인하고, EAFP는 연산을 시도한 뒤 예상한 실패를 잡아. 성공이 보통이고 실패가 예외라면 EAFP가 정상 흐름을 선명하게 만들고 확인과 사용 사이의 경쟁 조건도 없애.

미리 보는 편이 나을 때도 있어

실패가 대부분이거나, 시도 자체가 되돌릴 수 없는 부수 효과를 남기거나, ‘가능한가?’가 질문의 본체라면 LBYL이 정직해. 딕셔너리도 누락이 오류면 인덱싱과 예외, 흔한 경우면 get, 상태 확인 자체가 목적이면 in을 써.

원칙: EAFP는 무작정 돌진하는 태도가 아니라 시도와 실패 처리를 하나의 경계에 묶는 방법이야.

5% 관점: 손자병법 식으로 보면 승산을 묻지 않는 공격이 아니라, 확인과 실행 사이에 다른 일이 끼어드는 틈을 없애는 전술이야. 실패가 드물고 되돌릴 수 있을 때 시도와 처리를 묶고, 실패가 일상이거나 부수 효과가 크면 먼저 살펴.

Code

같은 문제를 LBYL과 EAFP로 풀기·python
d = {"x": 1, "y": 2}

# LBYL — Look Before You Leap
if "x" in d:
    value = d["x"]
else:
    value = 0

# EAFP — Easier to Ask Forgiveness than Permission
try:
    value = d["x"]
except KeyError:
    value = 0

# Python 에선 EAFP 가 일반적으로 idiomatic.
# 근데 dict 에 한정해선 .get() 이 더 좋음:
value = d.get("x", 0)
성공이 흔할 때의 EAFP·python
import time

d = {i: i*2 for i in range(10000)}

# LBYL — 매 접근마다 체크
def lbyl_sum():
    total = 0
    for i in range(10000):
        if i in d:
            total += d[i]
    return total

# EAFP — 그냥 접근, 드문 miss 만 raise
def eafp_sum():
    total = 0
    for i in range(10000):
        try:
            total += d[i]
        except KeyError:
            pass
    return total

# 대부분 접근 성공할 때 EAFP 가 빠름 (이중 확인이 없음)
start = time.perf_counter(); lbyl_sum(); print("LBYL:", time.perf_counter() - start)
start = time.perf_counter(); eafp_sum(); print("EAFP:", time.perf_counter() - start)
확인과 사용 사이의 경쟁 조건 없애기·python
import os

# LBYL — RACE CONDITION
if os.path.exists("data.txt"):
    # 체크와 open 사이에 파일 삭제되면?
    with open("data.txt") as f:
        contents = f.read()
# 동시성 / 외부 파일시스템 이벤트에 버그.

# EAFP — atomic
try:
    with open("data.txt") as f:
        contents = f.read()
except FileNotFoundError:
    contents = ""
# 체크와 사용 사이 창 없음. open이 성공하거나 곧바로 실패함.
부수 효과가 있으면 먼저 확인하기·python
# 부작용 있는 연산은 EAFP 가 절반에서 멈추면 나쁨
def create_directory(path):
    # LBYL — 먼저 체크, 안전할 때만 행동
    if os.path.exists(path):
        raise FileExistsError(f"{path} 이미 존재")
    os.makedirs(path)
    # os.makedirs 그냥 시도하고 FileExistsError 잡았다면
    # 더 복잡한 체크 (우리 거? 기존?)

# 여기선 LBYL 이 더 깔끔 — 연산이 non-idempotent.

External links

Exercise

문자열이 아닌 값도 섞인 haystack에서 needle의 등장 횟수를 세는 함수를 LBYL과 EAFP 두 방식으로 만들어. 앞은 타입과 포함 여부를 확인하고, 뒤는 count를 호출해 AttributeError를 처리해. 결과와 의도가 어떻게 다른지 비교해.

Progress

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

댓글 0

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

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