클로저(Closure) 함수
내부함수
클로저(Closure) 함수를 배우기 전에, 내부 함수에 대해 먼저 알아야 한다.
일급 객체 의 특징중에서 함수 내에 함수를 정의 할 수 있다고 했다. 이를 내부 함수(inner function)이라고 한다.
return c + dreturnprint()>>> 출력결과> 8
심화하기 : 내부 함수(inner function)은 루프나 코드 중복을 피하기 위해 또 다른 함수 내에 어떤 복잡한 작업을 한 번 이상 수행할 때 유용하게 사용한다.
클로저(closure) 1부 : 개념 익히기
위에서 간단하게 내부 함수가 무엇인지 배웠다. 내부 함수는 클로져(closure)처럼 행동할 수 있다.
클로저는 일반 함수와 다르게, 자신의 영역 밖에서 호출된 함수의 변수값과 레퍼런스를 복사, 저장, 접근을 가능하게 한다.
자세한 내용은 위키를 참고하자
return "안녕? 이걸 출력해줘! : {}".return say_sentencea =print("a는 무엇일까? : ", a)print("a의 타입은 무엇일까? : ", )print("a가 함수라는 걸 알았다. 괄호를 붙여보자. ====> ", )>>> 출력결과> a는 무엇일까? : <function say_words.<locals>.say_sentence at 0x7fc2c039c0d0>> a의 타입은 무엇일까? : <class 'function'>> a가 함수라는 걸 알았다. 괄호를 붙여보자. ====> 안녕? 이걸 출력해줘! : 출출하다
위 예제에서 내부 함수는 어떤 것인지 맞춰보자. say_sentece()
라는 함수다.
이 내부 함수는 "안녕? 이걸 출력해줘 ! : <msg값> " 을 리턴값으로 돌려준다.
그런데, say_sentece()
에 msg를 전달해준 적이 없는데도 메세지를 출력해준다!
이 말이 되는듯 아닌듯 말이 되는 것 같은 아리송함이 있다.
출력결과를 잘 살펴보자
a라는 변수에 say_words()
라는 함수를 할당 해줬는데,
a함수를 호출하니까 <function say_words.<locals>.say_sentence at 0x7fc2c039c0d0>
원래는 그냥 function
만 출력되야 한다. 지금 당장은 모르겠지만 아무튼 <locals>
가 붙는다.
이제 결론을 말해줄 수 있다.
결론 : 클로저는 다른 함수에 의해
동적
으로 생성되고, 바깥 함수로부터 생성된 변수값을 알고 있는 변수이다.
클로저(Closure) 2부 : 변수 추적하기
1부 요약 : 클로저는 바깥 함수로부터 생성된 변수를 어딘가에 저장한다. 그리고 이를 기억하고 있는다.
함수가 종료되도 클로저 함수가 기억하고 있는 변수는 메모리상에서 사라지지 않는다.
2부의 내용은 다른 블로그 를 참조해서 정리했다.
2부에서는 클로저는 바깥 함수의 변수를 어딘가에 저장하는데, 어디다가 저장하는지 추적 할 것이다.
1부 코드를 재활용하자.
return "안녕? 이걸 출력해줘! : {}".return say_sentencea =print("a는 무엇일까? : ", a)
추적 1단계 : print(dir(a))
dir(a) : 객체(a)가 자체적으로 가지고 있는 변수나 함수를 보여준다. 가장 큰 단위의 조사라고 보면 된다.
아래와 같은 결과가 나온다. a, b, c 순으로 출력되니까 __closure__를 찾아보자.
추적 2단계 : print(type(a.__clousre__)
dir()이라는 내장함수가 변수나 함수를 보여준다고 했으니까, 변수인지 함수인지 타입을 찍어보자.
추적 3단계 : print(a.__closure__)
오호, 그러면 타입을 알았으니까 튜플 값을 출력해보자.
cell : cell이 뭔가 찾아보니 여러 범위(scope)에서 참조할 수 있는 값을 저장할 수 있는 객체라고 한다.
print(len(a.__closure__)
로 길이를 살펴보니까 1
이 출력된다. 사실 위에서 <cell ~~~~> 이 괄호로 둘러쌓여있고, 쉼표(,) 뒤에 아무것도 없으니까 길이가 1이란 걸 알 수 있다.
추적 4단계 : print(dir(a__closure[0]__))
우리는 cell object의 특성을 잘 모른다. 그러니까 다시 dir()
을 찍어보자.
잡았다 요놈. 마지막에 cell_contents
를 숨기고 있었다.
추적 5단계 : print(a.__closure__[0].cell_contents)
드디어 추적이 끝났다. print(a.__closure__[0].cell_contents)
를 입력해보면
라는 허무한 메시지가 출력된다.
클로저(Closure) 3부 : 마무리
클로저(Closure)를 왜 쓰냐 다시 물어본다면 기존에 만들어진 함수나 모듈 등을 수정하지 않고 wrapper 함수를 이용해서 자기 입맛에 맞게 조정할 수 있다는 것이다.
'프로그래밍 > 파이썬' 카테고리의 다른 글
[파이썬] 제너레이터(Generator) 이해하기 (0) | 2017.05.21 |
---|---|
[파이썬] 데코레이터(Decorator) 이해하기 (3) | 2017.05.21 |
[파이썬] 일등 함수(first-class citizen) 이란? (2) | 2017.05.19 |
[파이썬] 리스트 컴프리헨션(list comprehension)의 이해 (1) | 2017.05.05 |
[파이썬] 행렬(matrix)과 리스트 컴프리헨션(list comprehension) 이해하기 (0) | 2017.05.05 |