C.W.K.
Stream
Lesson 02 of 05 · published

Comprehension / Generator / 맞는 모양

~18 min · comprehension, generator, idiom, pythonic

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

시퀀스 변환의 디폴트

"각 x 마다 y 생산" 하면 — Python 디폴트가 컴프리헨션. list 엔 [x*2 for x in xs], generator 엔 (x*2 for x in xs). for-loop-then-append 패턴은 컴프리헨션 안 맞을 때 손에 닿는 거지 반대 X.

map 와 filter — 보통 더 이상 Pythonic X

list(map(lambda x: x*2, xs)) 가 작동하지만 [x*2 for x in xs] 보다 안 읽힘. list(filter(lambda x: x > 0, xs))[x for x in xs if x > 0] 보다 안 읽힘. 예외 — 함수가 이미 named (list(map(str.upper, words))) 일 때 — 경쟁력 있음.

"시퀀스 한 번 처리" 엔 generator

컴프리헨션 결과가 한 번 소비되고 다시 반복 안 될 거면 대괄호를 괄호로 swap — sum(x*x for x in xs). 같은 로직, 중간 list X, 가능한 곳에 short-circuit. 큰 또는 무한 시퀀스 처리하는 코드의 큰 승리.

기술 — 모양 인식

pythonic 기술이 "어디나 컴프리헨션 사용" X. 변환이 거기 맞을 때 인식. 안의 로직이 두 줄이거나 분기 여러 개면 진짜 for-loop 짜거나 헬퍼 함수 추출. Pythonic = "복잡도에 문법 맞춤".

Pythonic Way: 한 줄 변환 디폴트로 컴프리헨션. reducer (sum, any, all, max) 에 먹이거나 source 가 거대할 때 디폴트로 generator. 원소별 로직이 단일 식 넘을 때만 명시적 loop.

Code

Comprehension vs loop — 같은 로직·python
# Loop
result = []
for n in range(10):
    if n % 2 == 0:
        result.append(n * n)

# 컴프리헨션 — 이 모양엔 선호
result = [n * n for n in range(10) if n % 2 == 0]
print(result)            # [0, 4, 16, 36, 64]
Comprehension vs map/filter·python
nums = [1, 2, 3, 4, 5]

# functional — wordy
result = list(map(lambda x: x * 2, filter(lambda x: x > 2, nums)))
print(result)            # [6, 8, 10]

# 컴프리헨션 — 직접
result = [x * 2 for x in nums if x > 2]
print(result)            # [6, 8, 10]

# 근데 named 함수 가진 map — 경쟁력
words = ["alpha", "beta"]
upper_a = list(map(str.upper, words))
upper_b = [w.upper() for w in words]
# 둘 다 OK. 컴프리헨션 약간 선호.
reducer 안의 generator — 효율적·python
# 컴프리헨션 — list 먼저 빌드
total = sum([x * x for x in range(1_000_000)])

# Generator expression — list X, 값 stream
total = sum(x * x for x in range(1_000_000))
# 같은 답, 메모리 훨씬 적음

# any/all/max/min/set 도 같은 idiom
any(x < 0 for x in nums)
max(x * 2 for x in nums)
set(x % 7 for x in range(100))
컴프리헨션 안 쓸 때·python
# 원소별 로직이 다단계일 때
result = []
for user in users:
    addr = lookup_address(user.id)
    if addr.country == "KR":
        if user.is_active:
            result.append({
                "name": user.name,
                "email": user.email,
                "address": addr.format(),
            })
# 이거 컴프리헨션에 쑤셔넣으면 안 읽힘.
# 명시적 loop 가 여기 더 pythonic.

External links

Exercise

각각 컴프리헨션 또는 generator 로 다시 짜 — (a) result = []; for x in nums: result.append(str(x)) (list comp). (b) 0-99 의 짝수 제곱의 합 (generator). (c) 이름 list 의 {name: len(name)} dict (dict comp). (d) 단어 list 의 유니크 첫 글자 set (set comp). 그 다음 — loop 본문이 user dict 의 5 줄 다단계 처리일 때 명시적 for-loop 가 보통 이기는 이유?

Progress

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

댓글 0

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

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