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

흔한 안티패턴 — 모양 뒤의 의도 바로잡기

~15 min · anti-pattern, common-mistake, style

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

작동하지만 다른 언어의 습관과 불필요한 방어를 끌고 온 코드가 있어. for i in range(len(seq))seq[i]를 쓴다면 enumerate가 보통 더 직접적이고, 딕셔너리에서는 원하는 것이 키·값·둘 다인지에 맞춰 기본 반복·values·items를 골라.

Noneis None으로 비교하고, def f(x=[]) 같은 가변 기본값은 호출 사이에 공유되므로 None을 기본으로 받아 안에서 새 값을 만들어. 인자 없는 exceptKeyboardInterrupt까지 잡으니 회복할 수 있는 구체적 예외를 잡고 나머지는 전파해.

측정 없는 최적화도 같은 부류야. 프로파일 전에 배열 요령이나 C 확장부터 고르면 느리지 않은 곳에 복잡성만 얹을 수 있어. 다만 안티패턴 목록도 금지표는 아니야. 실제로 인덱스만 필요한 range(len(seq))처럼 의도가 분명한 예외는 남겨.

Code

range(len()) 대신 enumerate 쓰기·python
items = ["a", "b", "c"]

# UNPYTHONIC
for i in range(len(items)):
    print(i, items[i])

# PYTHONIC
for i, x in enumerate(items):
    print(i, x)

# 페어 반복엔 zip
names = ["alice", "bob"]
ages = [30, 25]

# UNPYTHONIC
for i in range(len(names)):
    print(names[i], ages[i])

# PYTHONIC
for name, age in zip(names, ages):
    print(name, age)
None은 정체성으로 비교하기·python
x = None

# 덜 idiomatic
if x == None:
    print("missing")

# Idiomatic
if x is None:
    print("missing")

if x is not None:
    print("present")

# 드문 경우의 True/False 도 같음
# (그 경우엔 보통 그냥 `if x:` 또는 `if not x:` 가 더 좋음)
필요한 딕셔너리 뷰 고르기·python
d = {"a": 1, "b": 2, "c": 3}

# UNPYTHONIC
for key in d.keys():
    print(key, d[key])

# PYTHONIC
for key, value in d.items():
    print(key, value)

# 값만
for value in d.values():
    print(value)

# 키만
for key in d:                    # dict 반복하면 키
    print(key)
가변 기본값을 새로 만들기·python
# 안 좋음 — 공유 디폴트 list
def append_to(item, target=[]):
    target.append(item)
    return target

append_to("a")     # ['a']
append_to("b")     # ['a', 'b']    <- 버그

# 좋음 — None sentinel 패턴
def append_to(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

append_to("a")     # ['a']
append_to("b")     # ['b']         <- 새 list
회복할 예외만 좁게 잡기·python
# 안 좋음 — bare except
try:
    risky()
except:
    pass
# KeyboardInterrupt, SystemExit, MemoryError 등 잡음.

# 받아들일 만 — Exception 이 가장 넓은 합리적
try:
    risky()
except Exception as e:
    logger.error("unexpected: %s", e)

# 가장 좋음 — 특정
try:
    risky()
except (ValueError, KeyError) as e:
    handle_specifically(e)
# 다른 예외 전파 — 보통 맞음

External links

Exercise

자체 코드나 공개 Python 프로젝트에서 range(len()), 인자 없는 except, 가변 기본값, == None 가운데 세 가지를 찾아 의도를 보존한 채 고쳐. 못 찾으면 나쁜 예 세 개를 직접 만들고 다시 써서 패턴을 눈에 익혀.

Progress

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

댓글 0

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

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