파이썬(Python)

파이썬 - 함수 추가 내용(4)_Decorator & 재귀 함수

BlueNoa 2023. 1. 14. 19:32
728x90
반응형

•Decorator(데코레이터)

Decorator(데코레이터, 함수 장식자, Function Decorator)란 하위 클래스를 직접 사용하지 않고도 함수나 메소드 또는 클래스의 기능을 사용할 수 있다. 즉 Meta(데이터의 데이터) 기능이 있다는 것이다.

더 와닿을 수 있게 말을 하면 함수 장식자는 또 다른 함수를 감싼 함수라고도 표현할 수 있다.

메인 함수가 호출되면 그 반환값이 장식자에게 전달된다. 이 때 함수 장식자는 포함한 함수로 교체하여 함수를 반환한다.

 

글로만 표현하면 잘 와닿지 않기 때문에 다음 코드와 함께 보자.

# 예시용 함수 3개
def mark_1(fn):
    return lambda: "이것은 " + fn()
def mark_2(fn):
    return lambda: "함수를 " + fn()
def mark_3():
    return "감싼 것입니다."

# 함수 장식자를 사용하지 않고 표현하는 경우
ex = mark_1(mark_2(mark_3))
print(ex())

# 함수 장식자를 사용하는 경우
@mark_1
@mark_2
def ex2():
    return "함수에 감싼 것입니다."
print(ex2())


ex2_2 = ex2()
print(ex2_2) # 실행값을 가져온 경우
ex2_3 = ex2_2
print(ex2_3) # 주소값을 가져와 실행해도 된다.
이것은 함수를 감싼 것입니다.
이것은 함수를 함수에 감싼 것입니다.
이것은 함수를 함수에 감싼 것입니다.
이것은 함수를 함수에 감싼 것입니다.

참고로 위에서 'def 함수명(함수명):' <-- 이런 형태로 사용할 수 있는 것은 파이썬이 일급 함수의 특징을 갖고 있기 때문이다.

2023.01.11 - [파이썬] - 파이썬 - 함수 추가 내용(3)_일급 함수와 축약 함수(lambda)

 

파이썬 - 함수 추가 내용(3)_일급 함수와 축약 함수(lambda)

•일급 함수 임의의 함수를 다른 변수들처럼 동일하게 사용(다루는)할 수 있는 것을 의미한다. 일급함수로 정의되기 위해서는 조건이 있는데 함수 안에 함수(변수처럼)를 선언할 수 있어야 한다

bluenoa.tistory.com

 

(예시) 반지름을 입력했을 때 원의 넓이를 반환하는 함수를 만들자.

print('원의 넓이를 구하는 식')
def deco_1(fn): # 반지름 제곱해주기
    return lambda: int(fn()) ** 2 # 문자 -> 정수형

def deco_2(fn): # 파이 곱해주기
    def print_result():
        print(fn() * 3.14) 
    return print_result

def func(): # 반지름 입력
    cir_1 = input('반지름을 입력해주세요 : ') # 입력값은 문자로 들어간다.
    return cir_1

# 장식자 없이 표현
func1 = deco_2(deco_1(func))
func1()

# 장식자를 사용하여 표현
@deco_2
@deco_1
def func2():
    cir_2 = input('반지름을 입력해주세요 : ')
    return cir_2 
func2()
반지름을 입력해주세요 : 15
706.5
반지름을 입력해주세요 : 15
706.5

반지름으로 15를 입력했다. 사용하는 사람에 따라 입력값을 다르게 해주면 될 것 같다.


 

•재귀 함수(Recursive function)

재귀함수란 자기 스스로를 재참조하는 함수를 뜻한다.

즉 하나의 함수에서 자신을 다시 호출하여 작업을 수행하여 주어진 문제를 해결하는 방법이다.

(위 영상은 재귀함수를 재밌게 풀어낸 영상입니다.)

def TNT(n):
    if n == 0:
        print('펑!')
    else:
        print(n, end = ' ')
        TNT(n - 1) # 값을 하나 빼서 자기 자신을 호출
a = int(input('카운트다운 입력 : '))
TNT(a)

저는 10을 입력했습니다.

카운트다운 입력 : 10
10 9 8 7 6 5 4 3 2 1 펑!

 

(예시 - 피보나치 수열)

# 피보나치 수열 구현
li = []
def fibonacci(n):
    if n == 0 or n == 1:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

for i in range(6):
    li.append(fibonacci(i))
print(li)

반복문과 range(범위) 문을 사용했기 때문에 0~5의 자리수로 계산해야 한다.

[1, 1, 2, 3, 5, 8]

추가 range를 사용하지 않고 최종 값만 출력하는 경우 코드가 조금 바뀐다.

def fibonacci2(n):
    if n == 1 or n == 2:
        return 1
    else:
        return fibonacci2(n-1) + fibonacci2(n-2)

a = fibonacci2(6)
print(a)
8

 

(예시 - 팩토리얼)

# 팩토리얼 계산
print()
def facto(n):
    if n == 1 :
        print(n)
        return 1 # 1에서는 그냥 자기 자신을 리턴하고 끝남.
    print(n, end = ' ')
    return n * facto(n -1) # 자신의 값 * 이전의 값

print('결과 : ', facto(10))
10 9 8 7 6 5 4 3 2 1
결과 :  3628800

 

추가 예시

재귀함수를 이용해서 애플 매장에서 아이폰을 구매하는 간단한 코드를 작성해보도록 하자.

global Store_code
Store_Code = {1:'가로수길', 2:'여의도', 3:'명동', 4:'잠실'}
list_arr = [[0 for col in range(5)] for row in range(5)]
# print(list_arr)

# Store, Product, Quantity, Price, Amount
def Amount(price, quan): # 최종 물건 값을 계산하는 함수
    final_amount = int(price) * int(quan)
    return final_amount

def List_info(store, product, quan, price, amount, count): # 정보를 담는 역할
    list_arr[count][0] = Store_Code[store]
    list_arr[count][1] = product
    list_arr[count][2] = quan
    list_arr[count][3] = price
    list_arr[count][4] = amount

def list_show(count): # 출력
    for p in range(count):
        for q in range(5): 
            print(list_arr[p][q], end = '|')
            
def fun():
    count = 0 # 초기 개수는 0
    final_amount = 0 # 초기 금액 0
    print('지역정보 : 1:신사동, 2:여의도, 3:명동, 4:잠실')
    print('제품정보 : 아이폰14, 아이폰14pro')
    store_info, product, quan = input('매장정보, 제품명, 수량을 입력해주세요 : ').split(',') # ','로 입력값을 구분
    # print(store_info, product, quan) # 확인용
    
    while True:
        if product.strip() == '아이폰14': # split() : 기본값은 none, 띄어쓰기와 엔터를 구분하여 자른다.
            product = product.strip()
            price = 1250000
        elif product.strip() == '아이폰14pro':
            price = 1550000
            product = product.strip()
        else:
            print('상품명을 잘못입력했습니다.')
            break
            
        store = int(store_info) # 매장 정보를 숫자로 변환
        amount = Amount(price, quan) # 제품 가격을 계산
        List_info(store, product, quan, price, amount, count)
        
        final_amount += amount
        count += 1
        list_show(count)
        print('\n총 건수 : ' + str(count), '총액 : ' + str(final_amount))
        re_quest = input('주문을 계속하시겠습니까? [y/n]')
        if re_quest == 'y' or re_quest == 'Y':
            fun() # 자기 자신을 또 부른다.
        elif re_quest == 'n' or re_quest == 'N':
            print('주문이 완료되었습니다.')
            break # 종료

fun()

지역번호 : 1, 상품명 : 아이폰14, 수량 : 2

입력한 결과

지역정보 : 1:신사동, 2:여의도, 3:명동, 4:잠실
제품정보 : 아이폰14, 아이폰14pro
매장정보, 제품명, 수량을 입력해주세요 : 1, 아이폰14, 2
가로수길|아이폰14| 2|1250000|2500000|
총 건수 : 1 총액 : 2500000
주문을 계속하시겠습니까? [y/n]n
주문이 완료되었습니다.
728x90
반응형