728x90
"""
함수 데커레이터는 소스 코드에 있는 함수를 '표시'해서 함수의 작동을 개선할 수 있게 해준다.
강력한 기능이지만, 데커레이터를 자유자재로 사용하려면 먼저 클로저를 알아야한다.

파이썬 3.0에 추가된 nonlocal은 최근에 추가된 예약 키워드 중 하나다.
"""

"""
데커레이터는 다른 함수를 인수로 받는 콜러블(데커레이트된 함수)이다.
데커레이터는 데커레이트된 함수에 어떤 처리를 수행하고, 함수를 반환하거나 함수를 다른 함수나
콜러블 객체로 대체한다.
"""

"""
데커레이터의 핵심 특징은 데커레이트된 함수가 정의된 직후에 실행된다는 것이다.
이는 일반적으로 파이썬이 모듈을 로딩하는 시점, 즉 임포트 타임에 실행된다.
"""


def deco(func):
    def inner():
        print("running inner()")

    return inner()


@deco
def target():
    print("running target()")


# target 은 inner 함수를 가르키고 있음
target()


"""
데커레이터로 개선한 전략패턴
함수를 정의할때 코드를 반복하는 것은 피해야한다.
"""

promos = []


def promotion(promo_func):
    promos.append(promo_func)
    return promo_func


@promotion
def fidelity(order):
    """충성도 포인트 1000점 이상인 고객에게 전체 5% 할인 적용"""
    return order.total() * .05 if order.customer.fidelity >= 1000 else 0


@promotion
def bulk_item(order):
    """20개 이상의 동일 상품을 구입하면 10% 할인 적용"""
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += item.total() * .1
    return discount


@promotion
def large_order(order):
    """10종류 이상의 상품을 구입하면 전체 7% 할인 적용"""
    distinct_items = {item.product for item in order.cart}
    if len(distinct_items) >= 10:
        return order.total() * .07
    return 0


def best_promo(order):
    """최대로 할인받을 금액을 반환한다."""
    return max(promo(order) for promo in promos)


"""
빈 promos 리스트로 시작한다.
promotion() 데커레이터는 promo_func 를 promos 리스트에 추가한 후 그대로 반환한다.
@promotion 으로 데커레이트한 함수는 모두 promos 리스트에 추가된다.
best_promos()는 promos 리스트에 의존하므로 변경할 필요 없다.
"""
728x90