[Python] 클로저(closure)

cdwde·2021년 5월 15일
0

🎈 클로저란?

  • 어떤 함수의 내부 함수가 외부 함수의 변수를 참조할 때, 외부 함수가 종료된 후에도 내부 함수가 외부 함수의 변수를 참조할 수 있도록 어딘가에 저장하는 함수

  • 클로저 함수 조건
    - 어떤 함수의 내부 함수일 것
    - 그 내부 함수가 외부 함수의 변수를 참조할 것
    - 외부 함수가 내부 함수를 리턴할 것

def func(msg):
    message = 'Hello '+ msg
    def say():
        print(message)
    return say

f = func('python')
f()

#출력 결과
#Hello python

중첩 함수인 say가 외부 함수인 func의 변수 message를 참조하기 때문에
message 변수와 say의 환경을 저장하는 클로저가 동적으로 생성되었고
f가 실행될 때 해당 클로저를 참조해서 message 값 출력 가능!


🎈 클로저 저장 경로

1. dir()로 __closure__ 확인

dir(): 어떤 객체를 인자로 넣어주면 해당 객체가 어떤 변수와 메소드를 가지고 있는지 나열

def func(msg):
    message = 'Hello '+ msg
    def say():
        print(message)
    return say

f = func('python')

print(dir(f))

#출력 결과
#['__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__']

3번째 인덱스에 __closure__ 존재

2. __closure__ 값 확인

  • __closure__ 튜플은 모든 함수 객체가 가지고 있음 (클로저가 생성되지 않으면 None으로 고정)
def func(msg):
    message = 'Hello '+ msg
    def say():
        print(message)
    return say

f = func('python')

print(type(f.__closure__))
print(f.__closure__)
print(dir(f.__closure__[0]))

#출력 결과
#<class 'tuple'>
#(<cell at 0x0198F7D8: str object at 0x01AC8020>,)
#['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__ '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
  • type은 tuple
  • dir(f.__closure__[0]) 마지막에 cell_contents 존재

3. __closure__의 cell_contents 확인

❗ 클로저가 저장되는 경로 __closure__[0].cell_contents

def func(msg):
    message = 'Hello '+ msg
    def say():
        print(message)
    return say

f = func('python')

print(f.__closure__[0].cell_contents)

#출력 결과
#Hello python

🎈 언제 활용?

  • 지역 변수와 코드를 묶어서 사용하고 싶을 때

  • 클로저에 속한 지역 변수는 바깥에서 직접 접근할 수 없음
    => 데이터를 숨기고 싶을 때


🎈 lambda로 클로저 만들기

보통 클로저는 람다 표현식과 함께 사용하는 경우 많음

def calc():
    a = 3
    b = 5
    return lambda x: a*x + b

c = calc()
print(c(10))

#출력 결과
#35

참고
https://tibetsandfox.tistory.com/9
https://wikidocs.net/10307
https://dojang.io/mod/page/view.php?id=2366

0개의 댓글