Corey Schafer의 Programming Terms: Closures을 보고 정리합니다.
- First-Class Functions
- Closures
- Decorators
def outer_func():
message = 'Hi'
def inner_func():
print(message)
return inner_func()
outer_func()
>> Hi
outer_func
을 실행하면 message
에 Hi를 할당하고 inner_fuc
을 선언한다(실행은 아직 되지 않음). 그리고 마지막에 inner_func()
를 return하므로 inner_func
가 실행되고, 그제서야 print(message)
가 실행된다.
def outer_func():
message = 'Hi'
def inner_func():
print(message)
return inner_func
outer_func()
>>
만약 outer_func
에서 뒤에 괄호가 붙지 않는 inner_func
를 return하면 어떻게 달라질까? 결과는 아무것도 print되지 않는다.
그럼 다음과 같이 실행해보자.
my_func = outer_func()
print(my_func.__name__)
>> inner_func
my_func()
>> Hi
inner_func
를 return한다는 것은 함수를 실행시키는 것이 아니라, 함수 그 자체를 return하는 것이다. 그러므로 my_func = outer_func()
를 했을때 inner_func
가 return되며 my_func
는 inner_func
그 자체가 되는 것이다. 그리고 그 함수를 실행시키려면 뒤에 ()
를 붙여주면 된다.
여기서 재미있는 점은 분명 outer_func는 실행이 끝났는데, 우리가 return한 inner_func는 여전히 outer_func에서 할당해주었던 message 변수에 접근할 수 있다는 것이다. 그것이 바로 Closure이다.
간단히 말하자면, Closure는 outer function의 실행이 종료되었다고 하더라도, 생성된 local scope안의 변수를 기억하고 변수에 접근하는 inner function이다.
여기서 parameter를 추가해보자.
def outer_func(msg):
message = msg
def inner_func():
print(message)
return inner_func
hi_func = outer_func('Hi')
hello_func = outer_func('Hello')
hi_func
과 hello_func
는 argument로 받아온 message를 출력할 준비가된 inner function을 return한다.
inner_func
는 어떠한 argument도 필요하지 않기 때문에 그냥 ()
만 붙이면 실행된다.
hi_func()
>> Hi
hello_func()
>> Hello
위의 결과와 같이 이 function들은 그들 자신의 message variable의 값을 기억해둔 것을 알 수 있다. => A closure closes over the free variables(in this case, message variable) form their environment.
import logging
logging.basicConfig(filename='example.log', level=logging.INFO)
def logger(func):
def log_func(*args):
logging.info('Running "{}" with arguments {}'.format(func.__name__, args))
print(func(*args))
return log_func
def add(x,y):
return x*y
def sub(x,y):
return x-y
함수를 파라메터로 받는 logger
함수가 있다.
다음을 실행해보자.
add_logger = logger(add)
sub_logger = logger(sub)
각각 add
함수와 sub
함수를 outer function을 통해서 전달한다. 이제 두 함수를 우리의 inner function처럼 사용할 수 있게 된다.
add_logger(3, 3)
>>6
add_logger(4, 5)
>> 9
sub_logger(10, 5)
>> 5
sub_logger(20, 10)
>> 10
이 결과는 그냥 add
, sub
함수만을 이용해서 얻을 수 있는 결과지만 위와 같이 실행하면 다음과 같이 어떤 함수와 argument를 사용하였는지 기록되는 log 파일을 함께 생성할 수 있다.
INFO:root:Running "add" with arguments (3, 3)
INFO:root:Running "add" with arguments (4, 5)
INFO:root:Running "sub" with arguments (10, 5)
INFO:root:Running "sub" with arguments (20, 10)
outer function에서 arugment로 전달한 함수를 기억하여 inner_function에서 전달받은 *args
과 함께 한번에 기록된다.