[파이썬] 클로저

파이썬 2016. 11. 23. 22:16

중첩함수(nested function)

 

함수 안에 함수를 정의한 것을 말합니다.


중첩함수를 통해 default로 enclosing function local scope 변수를 참조할 수 있습니다.



내부 함수와 외부 함수


# -*- coding: utf-8 -*-


def outer_func(msg):

    def inner_func():
        print msg

    return inner_func


inner_func을 내부함수, outer_func를 외부함수라고 합니다.


inner_func 입장에서 outer_func 함수의 지역변수 영역을 enclosing function local scope(바깥 함수 지역 변수 영역) 라고 부릅니다.


 

클로저(closure)란


# -*- coding: utf-8 -*- def outer_func(msg): def inner_func(): print msg return inner_func my_func = outer_func("Megumin is so cute!!") my_func()

Megumin is so cute!!

내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가리킵니다.


inner_func가 outer_func의 지역변수인 msg를 참조하여 출력하는 것을 볼 수 있습니다.


함수를 변수에 저장할 수 있는 이유는 파이썬에서는 함수가 일급 객체(first-class object)이기 때문입니다.


# -*- coding: utf-8 -*-


def outer_func(msg):

    def inner_func():
        print msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()

second_func = outer_func("It's true")
second_func()

print
print "outer_func : ", id(outer_func), "\n"
del outer_func

first_func()
second_func()

print
print "first_func : ", id(first_func)
print "second_func : ", id(second_func)
Megumin is so cute!!
It's true

outer_func :  37766872 

Megumin is so cute!!
It's true

first_func :  37766984
second_func :  37767096


outer_func을 삭제해도 first_func가 정상적으로 호출됨을 알 수 있습니다.


이는 함수를 변수에 저장할 때마다 객체를 새롭게 생성하기 때문입니다.

(outer_func, first_func, second_func 모두 id 값이 다릅니다)


즉, first_func와 second_func는 서로 완전히 독립된 객체인 것입니다.



클로저 내에서 enclosing function local scope 변수 Read/Write



클로저에서 enclosing function local scope 변수에 접근할 수 있다면 modify 하는 것도 가능하지 않을까라고 생각할 수 있습니다. 


하지만 그것은 다음과 같은 오류를 보여줄 뿐입니다. 


# -*- coding: utf-8 -*-


def outer_func(msg):

    def inner_func():
        print msg
        msg = "Awesome!!"
        print msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
UnboundLocalError: local variable 'msg' referenced before assignment


첫 번째 print문에서 inner_func 함수 내에서 msg라는 변수는 선언된 적이 없기 때문에 enclosing function local scope에서 찾게 됩니다. 하지만 이 변수는 전역 변수와 마찬가지로 함수 내에서 수정할 수 없습니다. (파이썬 네임스페이스 참고)


그래서 python 3.x 부터는 nonlocal 이라는 키워드를 통해 외부함수 영역의 변수를 modify할 수 있도록 합니다.(nonlocal은 global과 비슷한 개념이라 할 수 있습니다)


python 3.x

# -*- coding: utf-8 -*-

def outer_func(msg):

    def inner_func():
        print(msg)
        nonlocal msg
        msg = "Awesome!!"
        print(msg)

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
Megumin is so cute!!
Awesome!!


다만, 별로 추천하지는 않다고 합니다.(보충 필요)



대신, python 2.x 에서는 내부 함수의 local variable에 enclosing scope의 변수를 저장하여 사용할 수 있습니다.

# -*- coding: utf-8 -*-


def outer_func(msg):

    def inner_func():
        _msg = msg
        print _msg
        _msg = "Awesome!!"
        print _msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
Megumin is so cute!!
Awesome!!


또는 함수 속성에 변수를 대입해도 가능합니다.

# -*- coding: utf-8 -*-


def outer_func(msg):

    def inner_func():
        inner_func.msg = msg
        print inner_func.msg
        inner_func.msg = "Awesome!!"
        print inner_func.msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
Megumin is so cute!!
Awesome!!



왜 사용할까


● 전역 변수의 사용을 피할 수 있음


● private 속성이 없는 파이썬에서 내부 데이터의 은닉을 할 수 있음


● 하나의 함수로 여러 가지의 함수를 간단히 만들어 낼 수 있도록 해줌


● 기존에 만들어진 함수나 모듈 등을 수정하지 않고도 wrapper 함수를 이용해 커스터마이징할 수 있게 해줌


(상세 설명 보충 필요)



요약



● 클로저란 내부 함수 영역에서 외부 함수 영역의 변수에 접근하는 것을 말함


● 파이썬에서 클로저가 구현 가능한 이유는 함수를 일급 객체로 취급하기 때문


● 클로저 내에서 외부 함수 영역 변수를 수정하기 위해서는 별도의 방법이 필요함


● 데이터 은닉 등의 목적을 위해 사용함



참고


[중첩함수]

https://www.programiz.com/python-programming/closure


[내부 함수와 외부 함수]

http://blog.naver.com/msyang59/220773717531


[클로저란]

https://slipp.net/questions/249

https://opentutorials.org/course/743/6544

http://jonnung.blogspot.kr/2014/09/python-easy-closure.html


[클로저 내에서 enclosing function local scope 변수 Read/Write]

[왜 사용할까]

http://schoolofweb.net/blog/posts/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%81%B4%EB%A1%9C%EC%A0%80-closure/


블로그 이미지

NCookie

,