[Python]클로저(Closure) 기초

파이썬의 Closure에 대해 알아보자

# 클로저(Closure) 기초

# 파이썬 변수범위(scope)
# 예1
b = 20

def func_v2(a):
    print(a)
    print(b)

func_v2(10)
print()
'''
10
20
'''

# 예2
c = 30

def func_v3(a):
    global c
    print(a)
    print(c)
    c = 40

print('>>', c)
func_v3(10)
print('>>>', c)
print()
'''
>> 30
10
30
>>> 40
'''

# 클로저(closure) 사용이유
# 서버프로그래밍 -> 동시성(Concurrency) 제어 -> 메모리 공간에 여러자원이 접근 -> 교착상태발생
# 메모리를 공유하지 않고 메시지 전달로 처리하기 위함
# 클로저는 공유하되 변경되지 않는(Immutable, Read only) 자료구조를 사용 -> 함수형 프로그래밍
# 클로저는 불변자료구조 및 atom, STM -> 멀티스레드(Coroutine) 프로그래밍에 강점


# 결과 누적(함수 사용)
print(sum(range(1, 11)))
print(sum(range(11, 101)))
print()
'''
55
4995
'''

# 결과 누적(클래스 사용)
class Averager():
    def __init__(self):
        self._series = []

    def __call__(self, v):
        self._series.append(v)
        print(f'inner >> {self._series} / {len(self._series)}')
        return sum(self._series) / len(self._series)

# 인스턴스 생성
averager_cls = Averager()

# 클래스를 함수처럼 사용
print(averager_cls(10))
print(averager_cls(20))
print(averager_cls(40))
'''
inner >> [10] / 1
10.0
inner >> [10, 20] / 2
15.0
inner >> [10, 20, 40] / 3
23.333333333333332
'''

# 클로저(Closure) 사용

def closure_ex():
    # free variable (자유영역 변수)
    # 클로저 영역
    series = []

    def averager(v):
        series.append(v)
        print(f'inner >> {series} / {len(series)}')
        return sum(series) / len(series)

    return averager

ex1 = closure_ex()

print(ex1)
print(ex1(10))
print(ex1(20))
print(ex1(40))
print()
'''
<function closure_ex.<locals>.averager at 0x000002859070E8C0>
inner >> [10] / 1
10.0
inner >> [10, 20] / 2
15.0
inner >> [10, 20, 40] / 3
23.333333333333332
'''


# function inspection
print(dir(ex1))
print()
print(dir(ex1.__code__))
print()
print(ex1.__code__.co_freevars)
print()
print(ex1.__closure__[0].cell_contents)
print()
print()
'''
['__annotations__', '__builtins__', '__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__']

['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lines', 'co_linetable', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames', 'replace']

('series',)

[10, 20, 40]
'''

# 잘못된 클로저 사용의 예
def closure_ex2():
    # free variable (자유영역 변수)
    cnt = 0
    total = 0
    def averager(v):
        cnt += 1
        total += v
        return total / cnt

    return averager

ex2 = closure_ex2()
# 오류 발생 : UnboundLocalError: local variable 'cnt' referenced before assignment
# print(ex2(10))


# closure_ex2 오류 수정
def closure_ex3():
    # free variable (자유영역 변수)
    cnt = 0
    total = 0
    def averager(v):
        nonlocal cnt, total
        cnt += 1
        total += v
        return total / cnt

    return averager

ex3 = closure_ex3()
print(ex3(10))
print(ex3(20))
print(ex3(40))
'''
10.0
15.0
23.333333333333332
'''

You may also like...

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다