ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Closure
    DynamicPL/Python 2019. 11. 7. 17:09

    1. Overview

    Closure can be consist of a function plus an extended scope that contains the free variables. 

    2. Description

    2.1 Free Variable and Inner Function

    Functions defined inside another function can access the outer (nonlocal) variables

    def outer():
        x = [1, 2, 3]
        print('outer:', hex(id(x)))
        def inner():
            print('inner:', hex(id(x)))
            print(x)
        return inner
        
        
    fn = outer()
    fn()

    x is a free variable in inner. It is bound to the variable x in outer this happens when outer runs that mean inner function is created. This the closure. When we return inner, we are actually "returning" the closure.

    We can assign that return value to a variable fn. When we called fn at that time python determined the value of x in the extended scope. But notice that outer had finished running before we called fn. Its scope was gone.

    2.2 Python Cells and Multi-scoped variables

    def outer():
        x = 'python'
        def inner():
            print(x)
        return inner

    Here the value of x is shared between two scopes

    • outer
    • closure

    The label x is in two different scopes but always reference the same value. Python does this by creating a cell as an intermediary object. In effect, both variables x (in outer and inner), point to the same cell. When requesting the value of the variable, Python will "double-hop" to get to the final value

    2.3 Closure

    You can think of the closure as a function plus an extended scope that contains the free variables. The free variable's value is the object the cell points to so that could change over time. Every time the function in the closure is called and the free variable is referenced. Python looks up the cell object, and then whatever the cell is pointing to 

    2.4 Multiple Instances of Closures

    Every time we run a function, a new scope is created. If that function generates a closure, a new closure is created every time as well.

    2.5 Shared extended scopes

    adders = []
    for n in range(1,4):
        adders.append(lambda x: x + n)
        
    adders[0](10)
    # 13
    adders[1](10)
    # 13
    adders[2](10)
    # 13

    n = 1: the free variable in the lambda is n, and it is bound to the "n" we created in the loop

    n = 2: the free variable in the lambda is n, and it is bound to the (same) n we created in the loop

    n = 3: the free variable in the lambda is n, and it is bound to the (same) n we created in the loop

    Python does not evaluate the free variable n until the adders[i] function is called. Since all three functions in adders are bound to the same n, by the time we call adders[0], the value of n is 3(the last iteration of the loop set n of 3)

    3. Example

    3.1 Introspection 1

    3.2 Introspection 2

    3.3 Nested Closures

    def incrementer(n):
    	# inner + n is a closure
        def inner(start):
            current = start
            # inc + current + n is a closure
            def inc():
                a = 10  # local var
                nonlocal current
                current += n
                return current
                
            return inc
        return inner
        
    # inner
    fn = incrementer(2)
    
    fn.__code__.co_freevars
    # 'n', n = 2
    
    # inc
    inc_2 = fn(100)
    
    inc_2.__code__.co_freevars
    # 'current, 'n', current = 100, n = 2
    
    # call inc
    inc_2()
    # 102, current = 102, n = 2
    
    
    inc_2()
    # 104, current = 104, n = 2

    4. References

    https://mathbyteacademy.com

    https://en.wikipedia.org/wiki/Closure_(computer_programming)

    'DynamicPL > Python' 카테고리의 다른 글

    Context manager  (0) 2019.11.09
    Decorators  (0) 2019.11.07
    First-Class Object and High-Order function  (0) 2019.11.02
    Slice  (0) 2019.10.28
    Sequence  (0) 2019.10.26

    댓글

Designed by Tistory.