[Python] 클로저(closure), 데코레이터
함수를 만들어 봔환하는 함수, 클로저(Closure)
>>> def maker(m):
def inner(n):
return m*n
return inner
>>> f = maker(2)
>>> f(7) # 실제 변수 m을 참조하게 되는 순간! maker함수의 밖이다.
14
함수를 반환하는 함수의 예이다. 파이썬의 함수는 객체이므로 다른 함수를 호출할 때 인자로도 전달이 가능하다.
maker함수의 m은 maker함수를 벗어나면 사라진다. 그런데 inner 함수에는 m*n 즉 m이 존재한다. m의 값을 참조하는 위치는 maker함수의 안이 아니라 다음 문장이 실행되는 maker함수 밖이다.
위 코드에서 정의한 inner 함수가 변수 m의 값을 어딘가에 살짝 저장해 놓고 쓴다.
이렇게 안쪽에 위치한 네스트드 함수가 자신이 필요한 변수의 값을 어딘가에 저장해 놓고 쓰는 테크닉을 클로저라 한다.
>>> def maker(m):
def inner(n):
return m*n
return inner
>>> f = maker(2)
>>> f.__closure__[0].cell_contents # 변수 m의 값을 저장해 놓은 위치
2
클로저는 네스티드 함수가 자신이 필요한 변수값을 어딘가에 저장해 놓는 기술이다. 그 위치는 위 코드로 확인이 가능하다. f.closure[0].cell_contents 의미는 변수의 인덱스 0의 위치에 저장된 객쳉듸 변수인 cell_contents이다.
데코레이터
데코레이터(Decorator)는 꾸며주는 역할을 하는 함수 또는 클래스이다.
>>> def smile():
print('^_^')
>>> def confused():
print('@_@');
>>> def deco(func): # 데코레이터 함수, 줄여서 데코레이터
def df():
print('emotion!') # 추가된 기능
func() # 원래 기능
print('emotion!') # 추가된 기능
return df # 보강된 기능의 함수를 반환
>>> smile = deco(smile) # 함수를 데코레이터에 통과시킴
>>> smile()
emotion!
^_^
emotion!
>>> confused = deco(confused)
>>> confused()
emotion!
@_@
emotion!
전달 인자가 있는 함수 기반의 데코레이터
>>> def adder2(n1, n2):
return n1+n2
>>> def adder3(n1, n2, n3):
return n1+n2+n3
>>> def adder_deco(func):
def ad(*args):
print(*args, sep='+', end=' ')
print("= {0}".format(func(*args)))
return ad
>>> adder2 = adder_deco(adder2)
>>> adder2(3,4)
3 + 4 = 7
위 코드에서 데코레이터를 정의하는데 있어서 튜플의 패킹과 언패킹이 사용되었다. 전달인자의 수에 상관없이 데코레이터를 정의했다.
@ 기반
def adder_deco(func): # 데코레이터 함수
def ad(*args):
print(*args, sep = ' + ', end = ' ')
print("= {0}".format(func(*args)))
return ad
@adder_deco # 아래 함수를 데코레이터 adder_deco에 통과시켜라
def adder2(n1, n2): # 전달 인자가 두 개인 함수
return n1 + n2
@adder_deco # 아래 함수를 데코레이터 adder_deco에 통과시켜라
def adder3(n1, n2, n3): # 전달 인자가 세 개인 함수
return n1 + n2 + n3
def main():
adder2(3, 4)
adder3(3, 5, 7)
main()
3 + 4 = 7
3 + 5 + 7 = 15
앞에서 보인 예제들은 함수정의와 데코레이터 통과 과정이 분리되어 있었다. 위 코드는 함수정의와 데코레이터 통과과정을 합쳤다.
데코레이터 함수 두번 이상 통과하기
def deco1(func): # 데코레이터 1
def inner():
print('deco1')
func()
return inner
def deco2(func): # 데코레이터 2
def inner():
print('deco2')
func()
return inner
@deco1
@deco2
def simple():
print('simple')
def main():
simple()
main()
deco1
deco2
simple
함수를 정의하면서 @기반으로 데코레이터를 두번이상 통과시킬 수 있다.
위 코드에서 simple = deco1(deco2(simple))를 하면 두번 통과시키는 것이다. 하지만 이것을 @기반으로 위 코드처럼 두번이상 통과가 가능하다.