"Pythonic" 이 문법 트릭에 관한 거 X. C 계열 언어와 다르게 만든 Python 문화의 load-bearing 가정 몇 개에 관한 거. 가장 큰 둘 — LBYL 보다 EAFP (시도, 예외 잡음, 모든 조건 미리 검증 X), duck typing (오리처럼 걷고 오리처럼 꽥꽥거리면 오리로 다뤄).
타입 X, 프로토콜 신뢰
Java 가 "이 메서드는 List 받음." Python 이 "이 메서드는 반복 지원하는 모든 거 받음." 첫 번째는 제한적 — generator, tuple, 커스텀 iterable 못 넘김. 두 번째는 유연 — __iter__ 구현하는 모든 거 작동. Python 문화가 이거에 강하게 기댐 — 함수가 duck-typed 입력 받고 caller 가 맞는 모양 선택.
실제 결과 — isinstance 체크 적음
Pythonic 코드가 반복 전 isinstance(x, list) 거의 안 체크. 그냥 반복. x 가 반복 지원 X 면 caller 가 잘못된 거 넘긴 거 — 자연스러운 에러 떠오르게. 'safe 하려고' isinstance 체크 추가가 유효 입력 (다른 iterable) 거부 + 노이즈 추가.
엄격 타입이 *이기는* 곳
타입 힌트 (typing 트랙) 가 런타임 isinstance 오버헤드 *없이* 정적 체킹. 힌트가 "Iterable 기대", mypy 가 검증, 런타임은 duck-typed. 현대의 타협 — 계약엔 구조 protocol (typing.Protocol), isinstance 벽 X.
원칙: Caller 가 뭐 하는지 알았다고 신뢰. 계약 문서화 (타입 힌트), 그 다음 메서드 호출. 무효 입력 에러가 한 번 fix 할 callsite 버그가 됨, 모든 합법 caller 처벌하는 검증 게이트 X.
Code
EAFP — Python 방법·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 문화에 매치
Duck typing — 어떤 iterable 도 받음·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}))
타입 힌트 + duck typing — 현대 타협·python
from typing import Iterable
def sum_typed(xs: Iterable[int]) -> int:
"""타입 힌트가 'int 의 iterable', 런타임은 duck-typed."""
return sum(xs)
# 타입 체커 (mypy) 가 caller 가 iterable 넘기는지 검증.
# 런타임이 isinstance-체크 X — 그냥 반복.
# 둘 세계의 best — 정적 계약, 런타임 유연성.
isinstance 가 *적절할* 때·python
# 시스템 경계에서 — 신뢰 X 데이터 검증:
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 방어성.
이 LBYL 함수를 EAFP 스타일로 다시 짜 + Iterable[int] 로 타입 힌트 추가 — def first_positive(items): if not isinstance(items, list): return None; for x in items: if isinstance(x, int) and x > 0: return x; return None. EAFP 버전이 tuple, generator, set 와 작동 하는데 LBYL 버전이 다 거부하는 거 보여.
Progress
Progress is local-only — sign in to sync across devices.