클로저(Closure)

  • First class function을 지원하는 언어의 네임 바인딩 기술
  • 어떤 함수를 함수 자신이 가지고 있는 환경과 함께 저장한 레코드
    • 클로저는 함수의 지역 변수 값을 그 함수가 종료된 후에도 기억
  • 함수가 가진 프리변수(Free Variable)를 클로저가 만들어지는 당시의 값과 레퍼런스에 매핑하는 역할
    • 프리변수(Free Variable) : 코드블럭 안에서 사용은 되지만 코드블럭안에서 정의 되지 않은 변수
  • 자신의 영역 밖에서 호출된 함수의 변수값과 레퍼런스를 복사하고 저장
  • 함수가 종료된 이후에도 참조가 가능한 것을 클로저(Closure)라고 함
# 예제 1
import time

def log_formatter(msg):
    def log_message():
        time_str = time.strftime('%c', time.localtime(time.time()))
        print(time_str, end='')
        print('------>', end='')
        print(msg) # MSG는 프리변수

    return log_message


log_msg = log_formatter('test log')
print(log_msg)
log_msg()

del log_formatter
try:
    print(log_formatter)
except NameError:
    print('log_formatter 함수는 존재하지 않습니다.')

log_msg()

msg는 log_formatter 함수가 종료되면 사라지는 Local namespace의 변수이다. 하지만 log_message를 클로저로 활용하여 함수가 종료된 이후에도 msg의 값을 출력할 수 있다.

# 예제 2
def outer_func():
    msg = 'Good Morning!'

    def inner_func():
        print(msg)

    return inner_func


func = outer_func()
print(func)

print(dir(func)) 				# dir(): 객체로 사용할 수 있는 멤버를 알려 줌
print(type(func.__closure__)) 	# closure의 type이 tuple인 것을 확인
print(func.__closure__) 		# closure는 cell 객체로 이루어짐
print(func.__closure__[0].cell_contents)	# cell_contents로 값을 확인
# 결과
<function outer_func.<locals>.inner_func at 0x000002A8ABB61948>
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
<class 'tuple'>
(<cell at 0x000002A8ABA399D8: str object at 0x000002A8ABA4D9F0>,)
Good Morning!

dir(func)을 통해서 func에서 객체로 사용할 수 있는 멤버에서 clouser가 있다는 것을 알 수 있다. func.__ closuer __의 타입이 tuplue이고 요소가 한개 인것을 알 수 있다.

그리고, func.__ clouser __의 0번째 요소의 cell_contents를 통해 클로저의 값을 확인 할 수 있다.