TIL 40. What is 'closure'?

Drageon Lee·2022년 2월 24일
0

TIL_Python

목록 보기
6/11

Today's topic

지난 posting에서 first class function에 대해서 정리해보았다. 이번 posting에서는 first class function에서 한 걸음 더 나아간 closure에 대해서 정리해 보도록 할 것이다.

👉 What is "closure"?

Closure은 어떤 함수의 내부 함수가 외부 함수의 변수(free variable : 함수 내에서 사용하지만 그 함수 내에서 정의 되지 않은 함수)를 참조할 때, 외부 함수가 종료된 후에도 내부 함수가 외부 함수의 변수를 참조할 수 있도록 어딘가 저장하는 함수를 뜻한다.
아래와 같은 조건을 충족해야 한다.

  • 어떤 함수의 내부 함수 일 것
  • 내부 함수가 외부 함수의 변수를 참조할 것
  • 외부 함수가 내부 함수를 return 할 것

👉 Example for 'closure'?

  • Closure 함수의 예시
    - 외부 함수와 내부 함수의 구조를 형성하고 내부 함수가 외부 함수의 변수를 받아서 사용한다. 여기서 프리 변수(아래 예시의 변수 명 : message)를 사용한다.
def logger(args):
    message = args
    def log_message():
        print('Log: ', message)

    return log_message


log_hi = logger('Hi')
log_hi()				# Hi가 출력

위의 code를 확인 시 결과 값으로 Hi가 출력되는 것을 확인 할 수 있다.
이 closure 함수에서는 한가지 짚고 넘어야 할 점이 있다.
정의에서도 언급 했듯이 closure 함수는 내부 함수가 외부 함수의 변수를 참조하기 위해 변수를 어딘가에 저장한다고 했다. 그럼 어디에 다가 저장을 하는 것일까?
안에 있는 함수가 밖에서 선언된 변수를 사용하는 것은 당연한게 아닌가 라고 생각될 수 있지만, 이 특성에 눈여겨 볼 필요가 있다.
이 것은 특정 속성에 의해서 가능한 것이다.

여기서 log_hi = logger('hi')에서 외부 함수에서 inner 함수(log_message)를 return하게 되면서 이 과정에서 이 함수에 closure 속성이 생기게 된다.

위에서 closure 함수가 충족할 조건 3가지를 충족시에 이 함수는 closure 함수가 되고 closure 속성을 가지게 된다.

'closure' 속성이란, dir() 명령어를 통해 유무를 확인 할 수 있다.
만약, 조건을 성립하지 못하면 외부 함수, 내부 함수가 있더라도 'closure' 속성을 가지고 있지 않는다.

  • example code(closure 함수)
def logger(args):
    message = args
    def log_message():
        print('Log: ', message)

    return log_message


log_hi = logger('Hi')
print(dir(log_hi))				# dir() 명령어로 확인 시 아래와 같은 결과 값을 확인

#'__closure__'을 확인
['__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__']
  • example code(외부 함수, 내부 함수는 있으나 return 값이 내부 함수가 아님)
def logger(args):
    message = args
    def log_message():
        print('Log: ', message)

    return message


log_hi = logger('Hi')
print(dir(log_hi))				# dir() 명령어로 확인 시 아래와 같은 결과 값을 확인

#'__closure__' 없음
['__add__', '__class__', '__contains__', '__delattr__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__',
'__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode',
'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index',
'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier',
'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper',
'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition',
'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust',
'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith',
'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

위의 예시 code를 확인 시 closure 함수의 조건을 만족했을 때만 'closure' 속성을 가지는 것을 알 수 있다.

그럼 여기에 뭐가 있는지 확인 해 보도록 하자!

def logger(args):
    message = args
    def log_message():
        print('Log: ', message)

    return message


log_hi = logger('Hi')

print(log_hi.__closure__)  
# (<cell at 0x100d31f70: str object at 0x100d43230>,) tuple 형태로 출력이 됨
print(log_hi.__closure__[0]) 
# <cell at 0x100d31f70: str object at 0x100d43230> log_message 오브젝트가 출력됩니다.
print(log_hi.__closure__[0].cell_contents)
# Hi가 출력 됨

위의 예제 code를 확인 시 free valiable이 'closure' 속성에 저장이 되어 있는 것을 알 수 있다.

👉 Why use 'closure'?

이제 까지 closure 함수에 대해 알아봤는데, 그럼 closure 함수는 왜 쓸까?
Closure 함수는 따로 global(전역) 변수를 사용하지 않는 경우에 사용할 수 있다. global 변수가 사용될 경우 program의 size가 커질 경우 디버깅이 힘들어 지기 때문에 이를 방지하기 위해 closure 함수를 사용하면 좋다.

또한, 이 개념은 decorator에서도 이어지게 된다.
다음 posting을 통해 decorator에 대해서 알아 볼 것이다.

📖 출처 :

My opinion

이번 posting을 통해 free valiable 및 closure 함수에 대해 정리해 보았다. 당연한 줄만 알았던 내용에 대해 세부적으로 파헤쳐 들어가면서 알아보니 신기하고 재미있었다. 앞에서 언급한 바와 같이 다음 posting에서는 decorator에 대해서 정리할 예정이다.

profile
운동하는 개발자

0개의 댓글