728x90
def make_averager():
    series = []

    def average(new_value):
        series.append(new_value)
        total = sum(series)
        return total/len(series)

    return average

 

make_averager() 는 그리 효율적이지 않다.
우리는 모든 값을 series 에 저장하고 average() 가 호출될 때마다 sum을 다시 계산했다.
합계와 항목 수를 저장 한 후 이 두개의 숫자를 이용해서 평균을 구하면 훨씬더 효율적으로 구현할 수 있다.

 

def make_averager2():
    count = 0
    total = 0

    def averager(new_value):
        count += 1
        total += new_value
        return total / count

    return averager

 

 

count가 수치형이거나 어떤 가변형일 때 count += 1 문이 실제로는 count = count + 1을
의미하기 때문에 문제가 발생한다.
따라서 averager() 본체 안에서 count 변수에 할당 하고 있으므로 count를 지역 변수로 만든다.
total 변수에도 동일한 문제가 발생한다.

 

make_averager() 함수에서는 series 변수에 할당하지 않기 때문에 이런 문제가 생기지 않았다.
단지 series.append 를 호출한 후 series에 sum과 len을 호출했을 뿐이다.
즉, 리스트가 가변형이라는 사실을 이용했을 뿐이다.

 

그러나 숫자, 문자열, 튜플 등 불변형은 읽을 수만 있고 값은 갱신 할수 없다.
count = count + 1 과 같은 문장으로 변수를 다시 바인딩하면 암묵적으로 count라는 지역 변수를 만든다.
count가 더이상 자유 변수가 아니므로 클로저에 저장되지 않는다.
이문제를 해결하기 위해 파이썬3에 nonlocal 선언이 소개 되었다.
변수를 nonlocal로 선언하면 함수 안에서 변수에 새로운 값을 할당하더라도 그 변수는 자유 변수임을 나타낸다.
새로운 값을 nonlocal 변수에 할당하면 클로저에 저장된 바인딩이 변경된다.
새로운 make_averager()를 올바르게 구현해보자.

 

def newMake_averager():
    count = 0
    total = 0

    def averager(new_value):
        nonlocal count, total
        count += 1
        total += new_value
        return total / count

    return averager
728x90

'Python > python - pythonic' 카테고리의 다른 글

del 과 가비지 컬렉션  (0) 2020.12.02
간단한 데커레이터 구현하기  (0) 2020.11.28
클로저 함수  (0) 2020.11.28
변수 범위 규칙  (0) 2020.11.27
데커레이터 함수 이해하기  (0) 2020.11.27