2

Python

Can anyone help me to understand this code, I am new to Python, how does this function work?

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

            return y + x
        return inc
    incOne = makeInc(1)
    incFive = makeInc(5)
    print(incOne(5)) # returns 6
    print(incFive(5)) # returns 10
Amal K
  • 4,359
  • 2
  • 22
  • 44
PRASOON
  • 23
  • 2
  • Perhaps this helps [Why aren't python nested functions called closures?](https://stackoverflow.com/questions/4020419/why-arent-python-nested-functions-called-closures) (for Python 2 but the argument should apply to Python 3). – DarrylG Jun 25 '21 at 09:27
  • 1
    Your makeInc function return inc function as value so when you call first function as incOne = makeInc(1) it sets value of x as 1 and return you inc function to call from incOne var again when you call incOne(5) it sets y =5 and compute the sum of x and y and return the value. It’s called nested functions – Abhishek Jun 25 '21 at 09:27

2 Answers2

3

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.

Amal K
  • 4,359
  • 2
  • 22
  • 44
1

What is happening here is that makeInc() returns a function handle pointing to specific implementation of inc(). So, calling makeInc(5) "replaces" the x in inc(y) to 5 and returns the callable handle of that function. This handle is saved in incFive. You can now call the function as defined (inc(y)). Since you set x=5 before, the result will be y+5.

ifumho
  • 141
  • 6