# Chapter05-04
"""
일급 함수(일급 객체)
클로저 기초
데코레이터(Decorator)
"""

# 데코레이터의 장점
# 1. 중복 제거, 코드 간결, 공통 함수 작성
# 2. 로깅, 프레임워크, 유효성 체크 -> 공통 함수, 기능(ex. 함수 실행 시간 측정 함수)
# 3. 조합해서 사용 용이

# 데코레이터의 단점
# 1. 가독성 감소?
# 2. 특정 기능에 한정된 함수는 -> 단일 함수로 작성하는 것이 유리
# 3. 디버깅 불편함

# 데코레이터 실습
import time

def perf_clock(func):
    def perf_clocked(*args):
        # 함수 시작시간
        st = time.perf_counter()
        # 함수 실행
        result = func(*args)
        # 함수 종료 시간
        et = time.perf_counter() - st
        # 실행 함수명
        name = func.__name__
        # 함수 매개변수
        arg_str = ', '.join(repr(arg) for arg in args)
        # 결과 출력
        print('[%0.5fs] %s(%s) -> %r' %(et, name, arg_str, result))
        return result
    return perf_clocked

@perf_clock
def time_func(seconds):
    time.sleep(seconds)

@perf_clock
def sum_func(*numbers):
    return sum(numbers)

# 데코레이터 미사용
none_deco1 = perf_clock(time_func)
none_deco2 = perf_clock(sum_func)

print(none_deco1, none_deco1.__code__.co_freevars)
print(none_deco2, none_deco2.__code__.co_freevars)

print("-"*30, 'called none Decorator -> time func')
print()
none_deco1(1.5)
none_deco2(1,2,3,4,5,6,7,8,9,10)

# 데코레이터 사용
print("-"*30, 'called Decorator -> time func')
print()
time_func(1.5)
sum_func(1,2,3,4,5,6,7,8,9,10)