← notes

Python - Decorators, Closures

2024-09-28 · python

[!TIP] Source 전문가를 위한 파이썬(Fluent Python) 15장

데커레이터

@decorate
def target():
	print('running target()')

#위 코드는 다음 코드와 똑같다
def target():
	print('running target()')
target = decorate(target)
@alpha
@beta
def f():
	#..

#이경우 다음과 같다
f = alpha(beta(f)) 

클로저

예를 들어

def make_averager():
	series =[]

	def averager(new_value):
		series.append(new_value)
		total = sum(series)
		return total/len(series)

	return averager


avg = make_averager()
avg(10) #10
avg(20) #15
avg(30) #20
def make_averager():
	count = 0
	total = 0

	def averager(new_value):
		nonlocal count, total
		count += 1
		total += new_value
		return total / count
	return averager

데커레이터 구현 예시

import time

def clock(func):
	def clocked(*args):
		t0 = time.perf_counter()
		result = func(*args)
		elapsed = time.perf_counter() - t0
		name = func.__name__
		arg_str = ', '.join(repr(arg) for arg in args)
		print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result))
		return result
	return clocked

@clock
def factorial(n):
	return 1 if n < 2 else n*factorial(n-1)

functools 헬퍼들

def clock(func):
	@functools.wraps(func)
	def clocked(*args):
		#...
import functools
import time

@functools.cache
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)
@functools.lru_cache(maxsize=5)  # 최근 5개 결과만 캐싱
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)
@functools.singledispatch
def process(value):
    raise NotImplementedError("지원되지 않는 타입!")

@process.register
def _(value: int):
    return f"정수 처리: {value * 2}"

@process.register
def _(value: str):
    return f"문자열 처리: {value.upper()}"

@process.register
def _(value: list):
    return f"리스트 처리: 길이 {len(value)}"

print(process(10))     # 정수 처리: 20
print(process("hello")) # 문자열 처리: HELLO
print(process([1, 2, 3])) # 리스트 처리: 길이 3

매개변수화된 데커레이터

def repeat(n):  # 데코레이터의 매개변수
    def decorator(func):  # 실제 데코레이터
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator  # 데코레이터를 반환

@repeat(3)  # repeat(3)이 실행된 후, 그 결과가 @데코레이터 역할을 함
def hello():
    print("Hello, world!")

hello()