- 클로져란?
-
정의되어 있는 스코프 안에 있는 변수를 참조하는 함수 (이 함수는 일급객체)
-
해당 변수와 바인딩 되어 있는 함수가 클로져.
-스코프
- 스코프, 즉 범위를 4개로 나눌 수 있다.
- 현재 함수의 스코프
- 현재 함수를 감싸고 있는 스코프
- 전역 스코프
- 내장 스코프
- 일급 객체 함수
- 일급객체 함수란?!
- 변수에 할당할 수 있고,
- 다른 함수의 인자로 전달할 수 있고,
- 표현식에서 사용될 수 있는 함수.
파이썬은 일급객체함수를 지원한다. 일급객체는 아래와 같이 크게 3가지 특성을 가진다고 정의할 수 있다.
def func1():
print('1st-class function')
a = func1 # 변수에 할당할 수 있고,
print(func1) # 다른 함수의 인자로 전달할 수 있고,
if func1:
print('expressive')
# 표현식으로 쓰일 수 있다.
# (return 될 수 있고, if문 등에 쓰일 수 있다.)
일급객체함수가 어떤 것인지를 이해했다면, 이제 클로져를 살펴보자.
밑의 함수를 보면,
def outer_func(a, b, *args, **kwargs):
def inner_func(x):
result = []
for val in x:
result.append((val+a)*b)
return result
return inner_func
outer_func
함수안의 스코프에 정의된 inner_func
함수를 일급객체로서 리턴하고 있다.
또한,
해당 inner_func
함수는 outer_func
에서 전달 받은 인자 a
와 b
를 사용하고 있다.
그렇다면, 여기서 가질 수 있는 한 가지 궁금증이 있다면!
a와 b는 outer_func
가 끝나면, 즉 outer_func
스코프 안에서만 역할하는 변수일텐데? 그 a와 b를 안에 품고, 리턴된 inner_func
에서는 어떻게 될까?!!!
이 궁금증에 대한 답이 바로 클로져이다!
이어서 밑의 예제를 보면,
myfunc1 = outer_func(2,10)
print(myfunc1)
# <function outer_func.<locals>.inner_func at 0x~~~~~~~~ >
print(myfunc1([1,2,3,4,5]))
# [30, 40, 50, 60, 70]
a
로 2를, b
로 10을 넘겨주었다. myfunc1
는 잘 작동을 한다???! 왜?!
넘겨주었던, 2와 10을 찾아보면,
print(myfunc1.__closure__[0].cell_contents)
# 2
print(myfunc1.__closure__[1].cell_contents)
# 10
해당 함수의 __closure__
의 리스트에서 cell_contents
로 접근할 수 있다.
이 처럼, 참조된 변수와 함께 바인딩 되어 있는 함수를 클로져라 한다.
(다시 기억해보자, 일급객체함수도 변수가 될 수 있다. 이 말은?! 함수자체도 함께 바인딩 될 수 있다.)
조금 더 생각해보자~
클로져는
마치, 함수가 상태를 가지고 있는 것 같다.
어디서 들어본 듯 하지 않는가??…
상태 + 행동, 거의 클래스네?!!
클로져를 활용해서~!
def outer_func(a, b, *args, **kwargs):
def inner_func1():
print("yeah")
def inner_func(x):
result = []
for val in x:
result.append((val+a)*b)
inner_func1()
return result
return inner_func
myfunc1 = outer_func(2,10)
print(myfunc1([1,2,3,4,5]))
# yeah
# [30, 40, 50, 60, 70]
클래스를 활용해서~!
class Inner_func:
def __init__(self, a, b):
self.a = a
self.b = b
def inner_func(self):
print("yeah")
def __call__(self, x):
result = []
for val in x:
result.append((val+self.a)*self.b)
self.inner_func()
return result
myfunc2 = Inner_func(2,10)
print(myfunc2([1,2,3,4,5]))
# yeah
# [30, 40, 50, 60, 70]
그렇네…. 물론 직접적으로 멤버변수, 메소드에 접근하는 .
의 활용 등은 안되지만,
클로져를 활용하면 어느 면에서는 마치 클래스처럼 상태 또는 메소드를 가지고 있듯이 함수를 사용할 수 있다.
이정도로만 일단 알아두자~!