클로저

매일 공부(ML)·2022년 12월 19일
0

Fluent Python

목록 보기
45/130

객체로서의 함수r

함수 데커레이터와 클로저

클로저

클로저는 익명 함수와의 개념 혼동이 일어나지만, 클로저는 함수 본체에서 정의하지 않고 참조하는 비전역 변수를 포함한 확장 범위를 가진 함수로, 함수가 익명 함수인지 여부는 중요하지 않고, 함수 본체 외부에 정의된 비전역 변수에 접근할 수 있다는 것이 중요하다.

#average_oo.py: 이동 평균을 계산하는 클래스

class Averager():
	
    def __init__(self):
    	self.series = []
        
    def __call__(self, new_value):
    	self.series.append(new_value)
        total = sum(self.series)
        return total/len(self.series)
        
# 고위 함수 활용한 이동 평균을 계산하는 함수 average.py

def make_averager():
	series = []
    
    def averager(new_value):
    	series.append(new_value)
        total = sum(series)
        return total/len(series)
        
    return averager
"""
호출 시 make_averager()는 average()함수 객체를 반환하고, average() 함수는 호출될 때마다 받은 인수를 series 리스트에 추가한다.
"""

#테스트
avg= make_vaerager()

클래스로 구현한 객체는 Averager()나 make_averager()를 호출해서 콜러블 객체인 avg가 반환되고, avg()는 series를 갱신하고 지금까지의 평균을 계산한다. avg()는 Averager 클래스의 객체고, 내부 함수인 average()이다.

재미있는 것은 Averager 클래스의 avg()함수가 데이터를 보관하는 방법을 명확히 알 수 있는데, 바로 self.series 객체 속성에 저장되기 때문이다. make_averager() 함수 본체 안에서 series=[]로 초기화하고 있으므로 series는 이 함수의 지역 변수이지만 new값을 호출 할 시 범위도 사라지는 것으로 average 안에 있는 series는 자유 변수(지역 범위에 바인딩 되어 있지 않은 변수)이다.



#make_averager()로 생성한 함수 조사하기
avg.__code__.co_varnames#{'new_value','total'}
avg.__code__.co_freevars#('series',)

series에 대한 바인딩은 반환된 avg() 함수의 closure속성에 저장되는 것으로, avg.closure의 각 항목은 avg.code.co_freevars의 이름에 대응되고, 이 항목은 cell 객체며, 이 객체의 cell_contents 속성에서 실제 값을 찾을 수 있다.


avg.__code__.co_freevars #('series',)
avg.__closure__
avg.__closure__[0].cell_contents

클로저는 함수를 정의할 때 존재하던 자유 변수에 대한 바인딩을 유지하는 함수로, 함수를 정의하는 범위가 사라진 후에 함수를 호출해도 자유 변수에 접근할 수 있으므로 함수가 비전역 외부 변수를 다루는 경우는 그 함수가 다른 함수ㅜ 안에 정의된 경우뿐이라는 점이다.

profile
성장을 도울 아카이빙 블로그

0개의 댓글