~20 min · functools, cache, partial, reduce, lru_cache
Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
함수 모양 유틸리티
itertools 가 iterable 용이면 functools 는 함수용. 결과 캐싱, 인자 currying, 시퀀스 reducing, 데코레이터 wrapper 간 메타데이터 보존. 첫 알아둘 4 — cache/lru_cache, partial, reduce, wraps (decorators 트랙에서).
cache + lru_cache — 무료 메모이제이션
@functools.cache (3.9+) 가 인자 기반으로 결과 캐시 — 같은 인자, 캐시된 값 반환. @lru_cache(maxsize=128) 가 같은데 bounded LRU 캐시. 순수 함수가 반복 호출에 극적으로 빨라져. 정석 데모 — 재귀 피보나치가 지수에서 선형으로.
partial — 인자 미리 바인딩
functools.partial(fn, *args, **kwargs) 가 일부 인자 미리 채워진 새 callable 반환. 더 적은 인자 기대하는 인터페이스에 함수 적응 — 콜백, sort key, 설정이 박힌 이벤트 핸들러로 넘기기.
reduce — iterable 위에 left fold
functools.reduce(fn, iterable) 가 왼쪽부터 누적적으로 fn 적용, iterable 을 단일 값으로 줄임. reduce(operator.add, [1, 2, 3]) 가 ((1+2)+3). reduce 의 대부분 사용은 이제 sum, min, max, 또는 컴프리헨션으로 더 잘 표현. 커스텀 결합 함수 필요할 때 손에 닿아.
War Story:cache 와 lru_cache 는 인자 해싱으로 작동. 함수가 unhashable 타입 (list, dict) 받으면 캐시 데코레이터가 raise. 해결 — hashable 형태로 변환하는 wrapper, 또는 더 옵션 있는 cachetools.
Code
cache + lru_cache — 메모이제이션·python
from functools import cache, lru_cache
import time
# 캐시 없이 — 재귀 피보나치 지수적
def fib_slow(n):
if n < 2:
return n
return fib_slow(n - 1) + fib_slow(n - 2)
# 캐시로 — 선형
@cache
def fib_fast(n):
if n < 2:
return n
return fib_fast(n - 1) + fib_fast(n - 2)
# fib_slow(35) ~3 초
# fib_fast(35) 즉시
print(fib_fast(50)) # 12586269025 — 거대한 n 에도 작동
# size 제한 lru_cache
@lru_cache(maxsize=128)
def expensive(x):
print("computing", x)
return x * x
print(expensive(3)) # computing 3, 9 반환
print(expensive(3)) # 캐시, 출력 X
print(expensive.cache_info()) # CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
(a) 이항 계수 (C(n, k) = C(n-1, k-1) + C(n-1, k)) 계산하는 재귀 함수에 @cache 적용 + 큰 입력 빠른지 확인. cache_info() 출력해서 hit/miss 봐. (b) partial 로 첫 인자가 [WARN] 으로 미리 바인딩된 print 인 log_warn 함수. (c) reduce + 커스텀 함수로 list 곱 계산 — math.prod 와 비교.
Progress
Progress is local-only — sign in to sync across devices.