~18 min · walrus, assignment-expression, short-circuit, or-default
Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
walrus 연산자 (3.8+) — :=
walrus 는 한 식 안에서 할당 + 평가. if (n := len(items)) > 10: 가 n 바인딩하고 결과 테스트. 사용처 — if/while 안의 read-and-test, 컴프리헨션 안에서 중간 값 캡쳐, 체인 안에서 재계산 피하기. 작은 기능인데 패턴 보이기 시작하면 의외로 넓게 쓰여.
or 디폴트 / and guard
x or default 은 x 가 truthy 면 x, 아니면 default. 좋음 — name = user_input or "anonymous". 조심 — 이건 *모든 falsy 값* 을 같이 취급. 0 이나 "" 가 합법적 사용자 입력이고 *없을 때만* fallback 하고 싶으면 x if x is not None else default 또는 명시적 체크.
다중 return path vs 단일 return
일부 스타일 가이드는 "함수당 return 하나" 외쳐. Python 은 그렇지 않아. 엣지 케이스 처리하는 early return ("guard clause" 패턴) 이 모든 걸 if 안에 중첩하는 것보다 보통 더 깔끔. 깊은 들여쓰기는 로직이 진짜 그걸 요구할 때 아껴 둬.
pass / ... / raise NotImplementedError
placeholder 세 가지 — pass (아무것도 안 함, 문 단위), ... (Ellipsis 리터럴, 문으로 받아들여짐, stub 파일과 추상 메서드에 idiomatic), raise NotImplementedError (서브클래스가 반드시 override 해야 한다는 신호). 선택은 *의도* 를 독자한테 말해 — no-op, stub, 미완성 메서드.
Pythonic Way: 함수가 "이거 아니면, 저거 아니면, 또 그거 아니면" 체크하고 다 깨끗할 때만 진행한다 — 부정 체크들을 early return 으로. 남은 코드는 happy path 에 들여쓰기 없이 살아. "guard clause" 패턴, validation 많은 코드의 가장 읽기 좋은 모양.
Code
walrus — if/while 안의 read-and-test·python
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# walrus 없이
n = len(items)
if n > 5:
print(f"big list ({n})")
# walrus 로 — 한 줄
if (n := len(items)) > 5:
print(f"big list ({n})")
# while 안에서 — 청크 단위 읽기
import io
stream = io.BytesIO(b"hello world this is some data")
while chunk := stream.read(8):
print(chunk)
# b'hello wo'
# b'rld this'
# b' is some'
# b' data'
컴프리헨션 안의 walrus·python
values = [10, 20, 30, 40, 50]
# walrus 없이 — 비싼 부분 매번 재계산
result = [v*v for v in values if v*v > 500]
# walrus 로 — 한 번 계산, 결과에 이름
result = [sq for v in values if (sq := v*v) > 500]
print(result) # [900, 1600, 2500]
or 디폴트와 falsy 함정·python
# or 디폴트는 0/빈값 = 없음 일 때 좋음
user_input = ""
name = user_input or "anonymous"
print(name) # 'anonymous'
# 근데 0 이 유효 값이면 or 디폴트 잘못됨
def get_quantity(x):
return x or 1 # 잘못됨: 0 도 1 로 변함
print(get_quantity(0)) # 1 <- 버그!
print(get_quantity(None)) # 1
# 맞음 — 명시적 None 체크
def get_quantity_v2(x):
return x if x is not None else 1
print(get_quantity_v2(0)) # 0
print(get_quantity_v2(None)) # 1
Guard clause — 들여쓰기 평탄화·python
# 중첩 if — 안 읽힘
def process_v1(user, msg):
if user is not None:
if user.is_active:
if msg:
if len(msg) <= 280:
return f"sending: {msg}"
else:
return "too long"
else:
return "empty"
else:
return "inactive"
else:
return "no user"
# Guard clause — 평탄한 happy path
def process_v2(user, msg):
if user is None:
return "no user"
if not user.is_active:
return "inactive"
if not msg:
return "empty"
if len(msg) > 280:
return "too long"
return f"sending: {msg}"
pass / ... / NotImplementedError — 세 placeholder·python
fetch_or_compute(cache, key, compute_fn) 작성 — cache[key] 있으면 반환, 없으면 compute_fn() 호출, 결과를 cache[key] 에 저장하고 반환. walrus 를 최소 한 번 써. 그 다음 validate_email(s) 의 guard clause 버전 — None, 빈 문자열, @ 없음, @ 두 개 이상, @ 뒤에 . 없음 중 하나라도면 "invalid", 아니면 "ok". 둘 다 최소 4 입력 테스트.
Progress
Progress is local-only — sign in to sync across devices.