Why Aren't Python Nested Functions Called Closures

Why aren't python nested functions called closures?

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.

Can anybody explain about the closure of function in Python?

Higher-order functions


Functions like makeInc that in turn, return another function are called higher order functions. Usually, functions are known to accept data as input and return data as output. With higher order functions, functions instead of data, either return code as output or accept code as input. This code is wrapped into a function. In Python, functions are first class citizens which means functions, just like data, can be passed around. For instance:

myvariable = print

Notice, how I have assigned print to myvariable and how I have dropped the parentheses after print Functions without parentheses are called function objects. This means myvariable now is just another name for print:

print("Hello World!")
myvariable("Hello World!")

Both of the above statements do the exact same thing. What can be assigned to variables can also be returned from functions:

def myfunction():
return print

myfunction()("Hello World!");

Now let's look at your example:

def makeInc(x):
def inc(y):

return y + x
return inc

makeInc is a function that accepts a parameter called x. It then defines another nested inner function called inc which takes in a parameter called y. The thing about nested functions is that they have access to the variables of the enclosing function as well. Here, inc is the inner function but it has access to x which is a variable of the enclosing outer scope.
The last statement return inc returns the inner function to the caller of makeInc. What makeInc essentially is doing, is creating a custom function based on the parameter it receives.
For instance:

x = makeInc(10)

makeInc will first accept 10 and then return a function that takes in an argument y and it increments y by 10.
Here, x is a function that takes in any argument y and then increments it by 10:

x(42) # Returns 52

nonlocal

However, there is a caveat when using nested functions:

def outer():
x = 10
def inner():
x = 20
inner()
print(x) # prints 10

Here, you would assume that the last print statement will print 20. But no! When you assign x = 20 in the inner function, it creates a new local variable called x which is initialized to 20. The outer x remains untouched. To modify the outer x, use the nonlocal keyword:

def outer():
x = 10
def inner():
nonlocal x = 20
inner()
print(x) # prints 20

If you are directly reading x inside inner() instead of assigning to it, you do not need nonlocal.

Python closures, create new int with different ID for every nested function

The issue is that you're not really creating a closure, you're just giving it the same lambda each time.

Instead you can return a function that binds the value of i:

from threading import Thread
from time import sleep

def call(time,f):
def caller():
sleep(time)
f()
Thread(target=caller).start()

def bind(i):
return lambda: print(i)

def func():
for i in range(1,6):
call(i, bind(i))

func()

bind returns a function where the value of i is "closed over", or as you appropriately called it, a closure.

Having a hard time understanding nested functions

The important thing here is that in Python, functions themselves are objects, too. Functions can return any type of object, so functions can in principle also return functions. And this is what echo does.

So, the output of your function call echo(2) is again a function and echo(2)("hello") evaluates that function - with "hello" as an input argument.

Maybe it is easier to understand that concept if you would split that call into two lines:

my_function_object = echo(2)   # creates a new function
my_function_object("hello") # call that new function

EDIT

Perhaps this makes it clearer: If you spell out a function name without the brackets you are dealing with the function as an object. For example,

x = numpy.sqrt(4)    # x is a  number
y = numpy.sqrt # y is a function object
z = y(4) # z is a number

Next, if you look at the statement return echo_word in the echo function, you will notice that what is returned is the inner function (without any brackets). So it is a function object that is returned by echo. You can check that also with print(echo(2))

Can you explain closures (as they relate to Python)?

Closure on closures

Objects are data with methods
attached, closures are functions with
data attached.

def make_counter():
i = 0
def counter(): # counter() is a closure
nonlocal i
i += 1
return i
return counter

c1 = make_counter()
c2 = make_counter()

print (c1(), c1(), c2(), c2())
# -> 1 2 1 2


Related Topics



Leave a reply



Submit