Why aren't python nested functions called closures?

后端 未结 8 637
情歌与酒
情歌与酒 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:02

    The question has already been answered by aaronasterling

    However, someone might be interested in how the variables are stored under the hood.

    Before coming to the snippet:

    Closures are functions that inherit variables from their enclosing environment. When you pass a function callback as an argument to another function that will do I/O, this callback function will be invoked later, and this function will — almost magically — remember the context in which it was declared, along with all the variables available in that context.

    • If a function does not use free variables it doesn't form a closure.

    • If there is another inner level which uses free variables -- all previous levels save the lexical environment ( example at the end )

    • function attributes func_closure in python < 3.X or __closure__ in python > 3.X save the free variables.

    • Every function in python has this closure attributes, but it doesn't save any content if there is no free variables.

    example: of closure attributes but no content inside as there is no free variable.

    >>> def foo():
    ...     def fii():
    ...         pass
    ...     return fii
    ...
    >>> f = foo()
    >>> f.func_closure
    >>> 'func_closure' in dir(f)
    True
    >>>
    

    NB: FREE VARIABLE IS MUST TO CREATE A CLOSURE.

    I will explain using the same snippet as above:

    >>> def make_printer(msg):
    ...     def printer():
    ...         print msg
    ...     return printer
    ...
    >>> printer = make_printer('Foo!')
    >>> printer()  #Output: Foo!
    

    And all Python functions have a closure attribute so let's examine the enclosing variables associated with a closure function.

    Here is the attribute func_closure for the function printer

    >>> 'func_closure' in dir(printer)
    True
    >>> printer.func_closure
    (,)
    >>>
    

    The closure attribute returns a tuple of cell objects which contain details of the variables defined in the enclosing scope.

    The first element in the func_closure which could be None or a tuple of cells that contain bindings for the function’s free variables and it is read-only.

    >>> dir(printer.func_closure[0])
    ['__class__', '__cmp__', '__delattr__', '__doc__', '__format__', '__getattribute__',
     '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
     '__setattr__',  '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
    >>>
    

    Here in the above output you can see cell_contents, let's see what it stores:

    >>> printer.func_closure[0].cell_contents
    'Foo!'    
    >>> type(printer.func_closure[0].cell_contents)
    
    >>>
    

    So, when we called the function printer(), it accesses the value stored inside the cell_contents. This is how we got the output as 'Foo!'

    Again I will explain using the above snippet with some changes:

     >>> def make_printer(msg):
     ...     def printer():
     ...         pass
     ...     return printer
     ...
     >>> printer = make_printer('Foo!')
     >>> printer.func_closure
     >>>
    

    In the above snippet, I din't print msg inside the printer function, so it doesn't create any free variable. As there is no free variable, there will be no content inside the closure. Thats exactly what we see above.

    Now I will explain another different snippet to clear out everything Free Variable with Closure:

    >>> def outer(x):
    ...     def intermediate(y):
    ...         free = 'free'
    ...         def inner(z):
    ...             return '%s %s %s %s' %  (x, y, free, z)
    ...         return inner
    ...     return intermediate
    ...
    >>> outer('I')('am')('variable')
    'I am free variable'
    >>>
    >>> inter = outer('I')
    >>> inter.func_closure
    (,)
    >>> inter.func_closure[0].cell_contents
    'I'
    >>> inn = inter('am')
    

    So, we see that a func_closure property is a tuple of closure cells, we can refer them and their contents explicitly -- a cell has property "cell_contents"

    >>> inn.func_closure
    (, 
     , 
     )
    >>> for i in inn.func_closure:
    ...     print i.cell_contents
    ...
    free
    am 
    I
    >>>
    

    Here when we called inn, it will refer all the save free variables so we get I am free variable

    >>> inn('variable')
    'I am free variable'
    >>>
    

提交回复
热议问题