Why aren't python nested functions called closures?

后端 未结 8 603
情歌与酒
情歌与酒 2020-11-22 05:37

I have seen and used nested functions in Python, and they match the definition of a closure. So why are they called nested functions instead of closures<

8条回答
  •  南笙
    南笙 (楼主)
    2020-11-22 06:22

    People are confusing about what closure is. Closure is not the inner function. the meaning of closure is act of closing. So inner function is closing over a nonlocal variable which is called free variable.

    def counter_in(initial_value=0):
        # initial_value is the free variable
        def inc(increment=1):
            nonlocal initial_value
            initial_value += increment
            return print(initial_value)
        return inc
    

    when you call counter_in() this will return inc function which has a free variable initial_value. So we created a CLOSURE. people call inc as closure function and I think this is confusing people, people think "ok inner functions are closures". in reality inc is not a closure, since it is part of the closure, to make life easy, they call it closure function.

      myClosingOverFunc=counter_in(2)
    

    this returns inc function which is closing over the free variable initial_value. when you invoke myClosingOverFunc

     myClosingOverFunc() 
    

    it will print 2.

    when python sees that a closure sytem exists, it creates a new obj called CELL. this will store only the name of the free variable which is initial_value in this case. This Cell obj will point to another object which stores the value of the initial_value.

    in our example, initial_value in outer function and inner function will point to this cell object, and this cell object will be point to the value of the initial_value.

      variable initial_value =====>> CELL ==========>> value of initial_value
    

    So when you call counter_in its scope is gone, but it does not matter. because variable initial_value is directly referencing the CELL Obj. and it indirectly references the value of initial_value. That is why even though scope of outer function is gone, inner function will still have access to the free variable

    let's say I want to write a function, which takes in a function as an arg and returns how many times this function is called.

    def counter(fn):
        # since cnt is a free var, python will create a cell and this cell will point to the value of cnt
        # every time cnt changes, cell will be pointing to the new value
        cnt = 0
    
        def inner(*args, **kwargs):
            # we cannot modidy cnt with out nonlocal
            nonlocal cnt
            cnt += 1
            print(f'{fn.__name__} has been called {cnt} times')
            # we are calling fn indirectly via the closue inner
            return fn(*args, **kwargs)
        return inner
          
    

    in this example cnt is our free variable and inner + cnt create CLOSURE. when python sees this it will create a CELL Obj and cnt will always directly reference this cell obj and CELL will reference the another obj in the memory which stores the value of cnt. initially cnt=0.

     cnt   ======>>>>  CELL  =============>  0
    

    when you invoke the inner function wih passing a parameter counter(myFunc)() this will increase the cnt by 1. so our referencing schema will change as follow:

     cnt   ======>>>>  CELL  =============>  1  #first counter(myFunc)()
     cnt   ======>>>>  CELL  =============>  2  #second counter(myFunc)()
     cnt   ======>>>>  CELL  =============>  3  #third counter(myFunc)()
    

    this is only one instance of closure. You can create multiple instances of closure with passing another function

    counter(differentFunc)()
    

    this will create a different CELL obj from the above. We just have created another closure instance.

     cnt  ======>>  difCELL  ========>  1  #first counter(differentFunc)()
     cnt  ======>>  difCELL  ========>  2  #secon counter(differentFunc)()
     cnt  ======>>  difCELL  ========>  3  #third counter(differentFunc)()
    
    
      
    

提交回复
热议问题