Closure: Lazy Evaluation And Eager Evaluation

Properties

📝2024.08.09

📄똑똑하게 코딩하는법 코딩의 기술 51

📎 CHAPTER 2. 동등성과 혼동성

Lazy Evaluation

Closure Lazy Evaluation And Eager Evaluation

  • 함수 내부에 지역 객체를 생성하고 폐쇄적인 범위를 사용 하는 일급 함수를 다룰 때 지연 연산을 잊지 말아야한다.

    def make_adders(addends):
        funcs = []
        for addend in addends:
            print(f"for iter addend: {addend}")
            funcs.append(lambda x: print(f"x: {x}, addend: {addend}") or x + addend)
        return funcs
    
    if __name__ == "__main__":
        adders = make_adders([10, 100, 1000])
        for adder in adders:
            print(f"adder: {adder}")
            print(adder(5))

    Lazy Evaluation에 의하여 addend 는 반복문에 가장 마지막 값인 1000으로 산정 된다. 그 이유는 클로저가 폐쇄적인 범위를 사용 하는 일급 함수라는 것에 있다.

  • 동작 순서

  1. 반복문을 순회 하며 funcs 라는 List에 함수의 오브젝트 주소를 담아둔다.

  2. 반복문 순회가 끝나면 함수의 주소값이 담겨있는 List를 반환한다.

  3. adders 를 다시 순회 하면서 내부에 존재하는 함수 오브젝트 주소 값을 이용 하여 Callable 객체를 실행 시킨다.

    • 오브젝트 주소가 담겨져 있으며 최종적으로 메모리에 남아 있는 addend 값인 1000을 이용 하고 x에 파라미터 정보인 5를 사용 하게 된다.

  • 결과

    for iter addend: 10
    for iter addend: 100
    for iter addend: 1000
    adder: <function make_adders.<locals>.<lambda> at 0x7fd5d929e200>
    x: 5, addend: 1000
    1005
    adder: <function make_adders.<locals>.<lambda> at 0x7fd5d929e290>
    x: 5, addend: 1000
    1005
    adder: <function make_adders.<locals>.<lambda> at 0x7fd5d929e320>
    x: 5, addend: 1000
    1005
    x: 5, addend: 1000

Eager Evaluation

  • Lazy Evaluation 방식을 강제로 Eager Evaluation으로 변경 할 수 있다. 메모리의 마지막 값을 사용 했던 방식을 빗대어 보면 default 값을 지정 해주었을 때 상쇄 시킬 수 있을 것이다.

  • 기억 해보자면 파이썬은 언제나 객체를 참조하는 값을 사용하여 재사용률을 높힌다.

    def make_adders(addends):
        funcs = []
        for addend in addends:
            print(f"for iter addend: {addend}")
            funcs.append(lambda x, _addend=addend: print(f"x: {x}, addend: {_addend}") or x + _addend)
        return funcs
    
    
    if __name__ == "__main__":
        adders = make_adders([10, 100, 1000])
        for adder in adders:
            print(f"adder: {adder}")
            print(adder(5))
  • 달라진 점

    • 여기서 중요한 포인트는 함수 파라미터의 기본 값을 사용 했다는 점이다. _addend=addend 는 현재 값을 함수 내부에서 사용 할 수 있도록 객체 참조값을 넣어주었다.

    • Lambda 내부에서 Print 할 수 있다는 것에 또 한번 놀라운 사실임을 알 수 있다.

  • 결과

    addend: 10
    addend: 100
    addend: 1000
    adder: <function make_adders.<locals>.<lambda> at 0x7f76727ee200>
    x: 5, addend: 10
    15
    adder: <function make_adders.<locals>.<lambda> at 0x7f76727ee290>
    x: 5, addend: 100
    105
    adder: <function make_adders.<locals>.<lambda> at 0x7f76727ee320>
    x: 5, addend: 1000
    1005

Last updated