Closures

rang-dev·2020년 6월 17일
0

Corey Schafer의 Programming Terms: Closures을 보고 정리합니다.

  1. First-Class Functions
  2. Closures
  3. Decorators

Closure

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_funcinner_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_funchello_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과 함께 한번에 기록된다.


다음글: Decorators

profile
지금 있는 곳에서, 내가 가진 것으로, 할 수 있는 일을 하기 🐢

0개의 댓글