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

functools — 함수의 모양과 결과를 다루는 도구

~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

cache와 lru_cache

같은 해시 가능한 인자로 부른 순수 함수의 결과를 저장해 반복 계산을 줄여. cache는 제한이 없고 lru_cache는 최근 사용 기준으로 크기를 제한해. 외부 시간·파일·설정에 따라 답이 달라지는 함수라면 빠르게 틀린 값을 줄 수 있어.

partial과 reduce

partial은 일부 인자를 미리 묶은 새 호출값을 만들어 콜백 계약에 맞춰. reduce는 왼쪽부터 누적하지만 합·최솟값·최댓값처럼 이름 있는 내장 함수가 있으면 그쪽이 더 분명해.

wraps는 데코레이터에서 원래 함수 정보를 보존해.

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))            # 캐시 사용, 출력 없음
print(expensive.cache_info())  # CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
partial로 일부 인자 미리 묶기·python
from functools import partial

def multiply(x, y):
    return x * y

double = partial(multiply, 2)         # x=2 미리 바인딩
print(double(5))                      # 10
print(double(10))                     # 20

# 콜백에 유용
def on_event(event_type, payload):
    print(f"got {event_type}: {payload}")

login_handler = partial(on_event, "login")
login_handler({"user": "alice"})      # got login: {'user': 'alice'}

# kwargs 미리 바인딩
import json
pretty = partial(json.dumps, indent=2, sort_keys=True)
print(pretty({"b": 2, "a": 1}))
전용 리듀서가 없을 때 reduce 쓰기·python
from functools import reduce
import operator

# 대부분 reduce 가 빌트인 등가물 있음
print(sum([1, 2, 3, 4]))                                # 10
print(reduce(operator.add, [1, 2, 3, 4]))              # 10  (같음)

# reduce 가 값어치 — 커스텀 결합자
products = reduce(operator.mul, [1, 2, 3, 4], 1)       # 24
print(products)

# 커스텀 함수 — 가장 긴 문자열 찾기
words = ["hi", "hello", "hey", "howdy"]
longest = reduce(lambda a, b: a if len(a) >= len(b) else b, words)
print(longest)                                          # 'howdy'

# 근데 max() + key= 가 보통 더 명확
print(max(words, key=len))                              # 'howdy'
해시할 수 없는 인자와 캐시·python
from functools import cache

@cache
def sum_list(items):
    return sum(items)

try:
    sum_list([1, 2, 3])      # list 가 unhashable
except TypeError as e:
    print("잡음:", e)

# 우회 — 경계에서 hashable 타입으로 변환
@cache
def sum_tuple(items_tuple):
    return sum(items_tuple)

print(sum_tuple((1, 2, 3)))   # 작동

# 또는 wrapper
def sum_list_v2(items):
    return sum_tuple(tuple(items))

External links

Exercise

재귀 이항계수 함수에 @cache를 붙이고 큰 입력과 cache_info를 확인해. [WARN]을 미리 묶은 print partial을 만들고, reduce로 리스트 곱을 계산해 math.prod와 비교해.

Progress

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

댓글 0

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

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