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

코드를 unpythonic 하게 하는 패턴

대부분 "unpythonic" 코드가 잘못 X — 작동. 단지 불필요한 indirection, 무게 못 이기는 방어 코딩, 다른 언어에서 import 한 스타일. 이 패턴 인식 + 가지치기가 코드 짧게, 빨리 읽기, 유지 쉽게.

1. range(len(seq)) — 진짜 enumerate 원할 때

seq[i] 접근 위해 for i in range(len(seq)) 반복하면 거의 확실히 for i, x in enumerate(seq) 원함. 예외 — 진짜 값 안 필요할 때 (인덱스만, 어떤 계산용). 그래도 자문해.

2. None 비교에 == 사용

x == None 작동하지만 idiom X. x is None / x is not None 사용. None 이 싱글톤, identity 비교가 빠르고 더 잘 읽힘. True, False 비교하는 드문 경우에도 같음.

3. 장황한 dict 반복

키 view 의 key.foo() 안 쓰는데 for key in d.keys(): — 그냥 for key in d:. for key in d.keys(): print(d[key]) — 그냥 for value in d.values():. for key in d.keys(): print(key, d[key]) — 그냥 for key, value in d.items():.

4. 디폴트 mutable 인자

def f(x=[]) — 반복 다룸. 공유 디폴트 list 버그. def f(x=None): if x is None: x = [] 사용. 외워, 버그 미묘 + 도입 쉬움.

5. 너무 넓게 잡기

except: 가 KeyboardInterrupt 포함 BaseException 잡음. except Exception: 이 넓지만 받아들일 만. 더 좋음 — 회복 가능한 특정 예외 타입 잡음. 다른 예외 전파해야.

6. 측정 없이 최적화

premature 최적화가 버그 도입 종류. profile 먼저 (tooling 트랙), 시간 실제 있는 곳 최적화. 측정 전에 array skip, C extension 짜기, vectorize X — 안 느렸던 코드에 시간 보냄.

Code

range(len()) — 보통 잘못·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)
is None vs == 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:` 가 더 좋음)
Dict 반복 — 맞는 view 골라·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)
Mutable 디폴트 — 명백한 버그 fix·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()), bare except, mutable default, ==None. 각각 교정 버전. 자체 코드에 못 찾으면 일부러 나쁜 예 셋 + 다시 짜. 핵심 — 인식, 못 보는 패턴 fix X.

Progress

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

댓글 0

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

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