Python_09-2(Decorator)
Decorator(장식자)
지역함수(Local Function) : 함수 안에 정의한 함수(중첩 함수라고도 한다.)
- 지역함수가 선언된 함수를 outer function 지역함수는 inner function 이라고 한다.
- inner function은 outer function의 지역변수를 자유롭게 사용할 수 있다.
- 기본적으로 inner function은 outer function 안에서만 호출할 수 있다.
- 단 outer function이 정의된 inner function을 return value로 반환하면 밖에서도 호출 할 수 있다.
def 라(a): # outer function
def 마(): # inner function
print(a + 10)
마()
마()
마()
마()
b = 10
return 마
라(10) # 라 함수(outer function)에 parameter로 10 입력, 마 함수(inner function)에서 처리 가능하다
b = 라(1)
print(b)
b() # return 마로 반환했기에 11이 결과로 출력
# 변수 - global(전역) 변수, local(지역) 변수
# 변수의 사용범위 (scope) = 그 변수가 선언된 영역(block) 내에서 호출 가능.
# -> 하위 영역(block에서도 호출, 사용가능)
# 함수에서 global 변수의 값을 변경할 경우 : global 변수명
# inner 함수에서 outer 함수의 local 변수를 변경 : nonlocal 변수명
# 하위블록에서 상위블록 변수의 값을 변경할 수는 있지만 하지 않는 것이 좋다.
global_var = "Global (전역)변수"
print(1, global_var)
def outer():
global global_var # global 변수 선언
local_var = "Outer 함수의 local (지역)변수"
print(2, global_var)
print(3, local_var)
# 하위블록에서 global 변수값을 변경하려면 global 변수 선언한 뒤에 변경하면 된다.
global_var = "Outer에서 변경한 global_var의 값"
def inner():
# Outer 함수의 지역변수를 변경할 경우 - nonlocal 변수명 으로 선언을 먼저해야 한다.
nonlocal local_var # nonlocal 변수명 선언
inner_local_var = "inner 함수의 local (지역)변수"
print(4, global_var)
print(5, local_var)
local_var = "inner에서 변경한 local_var 의 값"
print('5-2', local_var)
print(6, inner_local_var)
inner()
outer()
# print(local_var) # 상위 블록에서는 하위블록의 local 변수는 호출되지 않는다.
Closure (클로저)
- 지역함수(Inner function)를 정의한 Outer function이 종료되어도 지역함수가 종료될 때까지 outer function의 지역변수들은 메모리에 계속 유지 되어 inner function에서 사용할 수 있다.
- 파이썬 실행환경에서 inner function이 종료될때 까지 outer function의 지역변수들(parameter포함)을 사용할 수 있도록 저장하는 공간이 closure이다.
결론 : inner 함수에서 outer 함수의 변수를 사용하는데 return됨으로서 outer에 있는 지역변수도 사용할 수 있게 만든다.
어렵게 생각하지말고 이해만 하도록 하자.
def outer():
outer_var = 10 # outer 함수의 지역변수
def inner():
print(outer_var) # inner 함수에서 outer 함수의 변수를 호출
return inner # inner 함수를 반환
f = outer() # f = inner 함수
f()
Decorator (장식자) : 기존의 함수를 수정하지 않고 그 함수 전/후에 실행되는 구문을 추가할 수 있도록 하는 함수를 말한다.
- 기존 함수코드를 수정하지 않고 새로운 기능의 추가를 쉽게 해준다.
- 추가기능을 다수의 함수에 적용할 수 있다.
- 함수의 전/후처리 하는 구문을 필요하면 붙이고 필요 없으면 쉽게 제거할 수 있다
def a():
print("안녕하세요.")
def b():
print("Hello!")
print("-"*50)
a()
print("-"*50)
print("-"*50)
b()
print("-"*50) # -> 호출하다보니 계속 함수 호출 전,후에 코드를 작성해야하는 것이 귀찮다.
def a():
print("-"*50)
print("안녕하세요.")
print("-"*50)
def b():
print("-"*50)
print("Hello!")
print("-"*50)
a()
a()
b()
a()
# 그리하여 함수 내부에 변경을 주어 호출하다 보니 변경점이 생기면 함수를 바꿔야 하는 일이 발생한다
# 그래서 함수를 수정하지 않고 전처리와 후처리에 기능을 추가하고 다양한 방식을 적용하는 것을 도와주는것이 Decorator이다.
def a():
print("안녕하세요.")
def b():
print("Hello!")
def equal_deco(func): # 파라미터 -> 함수를 받는다. -> original 기능을 실행할 함수
# inner함수 : original 함수 호출을 처리하는 함수. 함수 호출 전후로 해야할 것이 있으면 그 처리를 한다.
def wrapper():
print("="*30) # 전처리
func() # 원래 함수의 작업
print("="*50) # 후처리
return wrapper
# a()
a_f = equal_deco(a)
a_f() # 실행된(호출한) 함수 : wrapper()
a() # 이런식으로 전,후처리를 자유롭게 처리할 수 있다.
def sharp_deco(func):
def wrapper():
print("#"*30)
func()
print("#"*30)
return wrapper
# 데코레이터 함수에 오리지날 함수를 전달해서 호출 -> wrapper 함수를 반환값으로 받는다. -> wrapper 함수를 호출
a_f2 = sharp_deco(a)
a_f2()
b_f = equal_deco(b)
b_f()
Decorator 구현 및 사용
구현
1. 전/후처리 기능을 추가할 함수를 parameter로 받는다.
2. 그 함수 호출 전후로 추가할 기능을 작성한 지역함수를 정의한다.
3. 2번의 함수를 반환한다.
호출 : @decorator이름을 적용하고자하는 함수 선언전에 기술한다.
# decorator를 original 함수 정의시 추가하라고 선언
@equal_deco # @함수명 -> decorator 기능 한다.
def a2():
print("안녕하세요")
a2()
@sharp_deco
def a3():
print("안녕하세요")
a3()
def sharp_deco2(func):
# original 함수가 파라미터를 받을 경우 그것을 wrapper() 함수에 설정한다.
def wrapper(param):
print("#"*50)
result = func(param) # original 함수 호출
print("#"*50)
if len(result) < 7: # 조건 달기(decorator에서 exception 발생시킬 수 있다.)
raise Exception("결과값이 모자랍니다.")
# result = " " + result
return result
return wrapper
@sharp_deco2
def greet(name):
print(f"{name}님 환영합니다.")
return f"인사말 {name}"
# sharp_deco2.wrapper를 호출
v = greet("홍") # return되는 "인사말 {name}"이 7글자보다 작다는 조건에 만족되지 못하면 Exception 발생
print(v)