Asked  7 Months ago    Answers:  5   Viewed   52 times

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?

Are nested functions not closures because they are not used by the external world?

UPDATE: I was reading about closures and it got me thinking about this concept with respect to Python. I searched and found the article mentioned by someone in a comment below, but I couldn't completely understand the explanation in that article, so that is why I am asking this question.

 Answers

99

A closure occurs when a function has access to a local variable from an enclosing scope that has finished its execution.

def make_printer(msg):
    def printer():
        print msg
    return printer

printer = make_printer('Foo!')
printer()

When make_printer is called, a new frame is put on the stack with the compiled code for the printer function as a constant and the value of msg as a local. It then creates and returns the function. Because the function printer references the msg variable, it is kept alive after the make_printer function has returned.

So, if your nested functions don't

  1. access variables that are local to enclosing scopes,
  2. do so when they are executed outside of that scope,

then they are not closures.

Here's an example of a nested function which is not a closure.

def make_printer(msg):
    def printer(msg=msg):
        print msg
    return printer

printer = make_printer("Foo!")
printer()  #Output: Foo!

Here, we are binding the value to the default value of a parameter. This occurs when the function printer is created and so no reference to the value of msg external to printer needs to be maintained after make_printer returns. msg is just a normal local variable of the function printer in this context.

Tuesday, June 1, 2021
 
Tapha
answered 7 Months ago
23

When I run your code I get this error:

UnboundLocalError: local variable '_total' referenced before assignment

This problem is caused by this line:

_total += PRICE_RANGES[key][0]

The documentation about Scopes and Namespaces says this:

A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects.

So since the line is effectively saying:

_total = _total + PRICE_RANGES[key][0]

it creates _total in the namespace of recurse(). Since _total is then new and unassigned you can't use it in the addition.

Wednesday, June 2, 2021
 
Maury
answered 7 Months ago
77

The problem is in your scoping, not in your closures. If you're up for some heavy reading, then you can try http://www.python.org/dev/peps/pep-3104/.

If that's not the case, here's the simple explanation:

The problem is in the statement global get . global refers to the outermost scope, and since there isn't any global function get, it throws.

What you need, is an access specifier for variables in the enclosing scope, and not the global scope.

In python 3.0, as I've tested, the nonlocal keyword is exactly what you need, in the place of global.

nonlocal get
...

In python 2.x, I just removed the global get and the oldget references and it works properly.

Wednesday, August 4, 2021
 
bimal
answered 4 Months ago
22
def f1():
    x = { 'value': 5 }
    def f2():
        x['value'] += 1

Workaround is to use a mutable object and update members of that object. Name binding is tricky in Python, sometimes.

Sunday, August 8, 2021
 
NoSenseEtAl
answered 4 Months ago
61

You can check the bytecode with the dis module:

>>> import dis
>>> def my_function():
...     def little_function():
...             print "Hello, World!"
...     
... 
>>> dis.dis(my_function)
  2           0 LOAD_CONST               1 (<code object little_function at 0xb74ef9f8, file "<stdin>", line 2>)
              3 MAKE_FUNCTION            0
              6 STORE_FAST               0 (little_function)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE  

As you can see the code for the inner function is compiled only once. Every time you call my_function it is loaded and a new function object is created(in this sense the def little_function is executed every time my_function is called), but this doesn't add much overhead.

Sunday, August 15, 2021
 
Magnanimity
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share