/ PYTHON

(Python) 클로저란 with 일급객체


클로저를 알기위해서는 파이썬의 함수 특징에 대해 알아야 한다

일급객체란

변수 or 데이터 구조(자료구조) 안에 담을 수 있어야 한다
함수의 매개변수로 전달할 수 있어야한다
함수의 결과 반환값으로 사용될수 있어야 한다
실행시점에 초기화된다(런타임 초기화)

파이썬에서 함수는 일급 객체의 조건을 모두 만족한다. 함수를 변수에 할당할 수 있고, 인자로 전달이 가능하며, 함수의 리턴값으로도 사용될 수 있다

1. 함수가 변수로 할당

def factorial(n):
    """
    Factorial function -> n : int
    """
    if n == 1:
        return 1
    return n * factorial(n - 1)
var_func = factorial # 변수에 할당(함수를 변수에 할당하여 사용할 수 있다)
print(var_func) # <function factorial at 0x7fc10e385620> factorial함수가 할당됨을 알 수 있다
print(var_func(20))
print(list(map(var_func, range(1,5)))) # [1, 2, 6, 24]


2. 함수가 다른 함수의 매개변수로 사용

def factorial(n):
    """
    Factorial function -> n : int
    """
    if n == 1:
        return 1
    return n * factorial(n - 1)
var_func = factorial
print(list(map(var_func, filter(lambda x: x % 2, range(1, 6))))) # var_func가 filter함수의 인자로 전달


3. 함수가 리턴값으로 사용

def factorial():
    def result():
        print('this factorial function')
    return result # 함수값이 리턴됨
var_func = factorial()
var_func()



클로저(Closure)란

클로저는 어떤 함수의 내부 함수가 외부 함수의 변수를 참조할때 외부 함수가 종료된 후에도 내부 함수가 외부 함수의 변수를 참조할 수 있도록 어딘가에 저장하는 함수를 말한다. 즉 외부에서 호출된 함수의 변수값, 상태(레퍼런스) 를 복사 후 어딘가 저장한 다음 접근(액세스) 가능할 수 있게 도와준다

함수의 내부함수
내부 함수가 외부 함수의 변수를 참조
외부 함수가 내부 함수를 리턴

# closure 사용

def closure_ex1():
    # free variable : 어떤 함수에서 사용되지만 그 함수 내부에서 선언되지 않은 변수, 즉 지역도 전역도 아닌 변수
    # 클로저 영역
    series = [] # free variable로 self._series의 역할을 한다.
    def averager(v):
        series.append(v)
        print('inner >>> {} / {}'.format(series, len(series)))
        return sum(series) / len(series)
    return averager # 일급함수 특징중 함수의 결과 반환 가능
avg_closure1 = closure_ex1()
print(avg_closure1) # <function closure_ex1.<locals>.averager at 0x7f368c2078c8>
print(avg_closure1(10))
print(avg_closure1(20))


closure_ex1함수의 역할이 끝나면 series도 소멸되어야 하지만 중첩 함수인 averager의 외부 함수인 closure_ex1의 변수 Series와 averager의 환경을 저장하는 클로저가 생성된다. 클로저는 dir을 통해 저장된 위치 등을 알 수 있다

print(dir(avg_closure1))
print()
print(dir(avg_closure1.__code__))
print(avg_closure1.__code__.co_freevars) # ('series',) free variable 즉, 자유변수가 소멸되지 않고 저장되는 공간이다.
print(avg_closure1.__closure__[0].cell_contents) # 클로저가 저장 되는 경로라고 보면 된다