본문 바로가기
C++,python (인프런+사이트)/python 파이썬 정리

Closure 클로저

by 알 수 없는 사용자 2022. 4. 3.

클로저에 대한 개념은 Class로 구현한 Closure에 써놈

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

 

클로저 정리 : 한 클래스 or 함수 내에서 shared 데이터 쓰는거 마냥 data를 공유(공통)으로 쓰는 방식

 

말로풀자면 작업 1,2,3,4,5 가 있는데

1작업이 30% 정도 진행되고 있고 2작업이 급하게 해야하는 상황일때, 

1작업을 중단하고 2작업을 끝낸 후, 1의 작업을 마저 한다.  라는 기능이 가능해지는 격

1작업스코프를 벗어났음에도 1작업이 어디까지 했는지 알 수 있기 때문에 이런 기능이 구현됨


보기전에 봐야될 개념

내부 함수 depth에 따라서 지역,비지역 함수가 나뉜다.

# outer(), inner() 함수 입장에서 전역(global) 범위
def outer():
    # outer() 함수 입장에서 지역(local) 범위
    # inner() 함수 입장에서 비지역(nonlocal) 범위
    def inner():
        # inner 함수 입장에서 지역(local) 범위

 


주로 봐야될 부분은

1. 클로저 형식

2, 잘못된클로저 사용 (mutable VS immutable  임뮤타블일땐 nonlocal을 사용해줘야한다.)

3. 클로저기능이 되는 이유

 

1. 클로저 형식 ( call by reference , mutable 인 경우 )

----(1). 외부함수의 자유변수를 내부함수에서 사용한다

----(2). 외부함수에서 내부함수를 return 해준다 ★★ 여기서 "averager()" 가 아니라 "averager" 이렇게 리턴

----(3). 내부함수에서 외부함수의 자유변수를 return해줘야함

2. 클로저의 잘못된 예 ( call by value , immutable 인 경우 )

int형은 immutable 즉 call by value임.  따라서 nonlocal을 써줘야함

외부함수의 변수는 내부함수에서 읽기는 가능하지만 쓰기가 불가능 하다.

[ ] 리스트는 mutable이므로 읽고 쓰기가 가능. 왜냐면 쓰기를 해도 ID주소가 바뀌지 않기때문

 

3. 클로저 제대로 쓴 예 ( call by value , immutable 인 경우 )

immutable(call by value) 인 int형 값을 클로저로 사용 하고 싶으면 

"nonlocal" 로 Free Variable(nonlocal지역)을 명시해줘서 써야 한다.

 

4.

avg_closure1 = closure_ex1()

print(avg_closure1.__code__.co_freevars # avg_closure1() 외부함수의 FreeVars 값 retrun
print(avg_closure1.__closure__[0].cell_contents# FreeVars 값에 들어간 data 확인이 가능하다

이 두 함수를 프린팅 해보면 알 수 있다

closure 기능을 씀으로써 자유변수에 대한 data가 따로 복사되어 사용가능한거임

콘솔창


 

전체 코드

# Chapter05-03
# 파이썬 심화
# 클로저 심화

# 클로저(Closure) 사용
def closure_ex1():
    # Free variable 자유변수
    series = []
    # 클로저 영역
    def averager(v):
        # series = [] # 주석 해제 후 확인
        series.append(v)
        print('inner >>> {} / {}'.format(series, len(series)))
        return sum(series) / len(series)
    
    return averager


avg_closure1 = closure_ex1()

print(avg_closure1(15))
print(avg_closure1(35))
print(avg_closure1(40))

print()
print()

# function inspection

print(dir(avg_closure1))
print()
print(dir(avg_closure1.__code__))
print()
print(avg_closure1.__code__.co_freevars)
print()
print(dir(avg_closure1.__closure__[0]))
print()
print(avg_closure1.__closure__[0].cell_contents)

print()
print()


# 잘못된 클로저 사용
def closure_ex2():
    # Free variable
    cnt = 0
    total = 0

    def averager(v):
        cnt += 1 # cnt = cnt + 1
        total += v
        return total / cnt
    
    return averager

avg_closure2 = closure_ex2()

# print(avg_closure2(15)) # 예외


# Nonlocal -> Free variable
def closure_ex3():
    # Free variable
    cnt = 0
    total = 0
    
    def averager(v):
        nonlocal cnt, total
        cnt += 1
        total += v
        return total / cnt
    
    return averager

avg_closure3 = closure_ex3()

print(avg_closure3(15))
print(avg_closure3(35))
print(avg_closure3(40))

print()
print()

 


 

댓글