Help needed to understand function closures and partial please

Hello dear DQ community,

I’m currently in the middle of Building a Pipeline Class in the Data Engineering path and I must admit I’m a bit struggling with the partial module and function closures.

So for instance in
Screen Link:

The Code is :

def add(A):
    def inner(b):
        # Use `A` from the argument in 
        # the parent add() function.
        return A + b
    return inner

add_two = add(2)
print(add_two(7))

My understading is the following
add_two is a variable that stores the returned value of the add function.
The add function accepts one parameter, in this case A.

The point where it gets troubling for is:

  • where else is add_two defined so that it can accept a parameter too?
    Because clearly the inner function, aptly even though generecally called inner, accepts the parameter b and from the example it is provided by the add_two variable/function.

As I do everytime I get stuck, I tried tweaking the code snippet to better grasp the inner working.
But print(add_two) outputs the memory location of the variable so it’s of no use
And print(add_two()) outputs the traceback TypeError: inner() missing 1 required positional argument: 'b'

So this confirms that inner and add_two are linked.
The following paragraph in the lesson supposed to explain it confuses me even more :frowning:

Finally, notice that when we call the add() function with 2, the inner() function is returned to the add_two variable with the saved parent variable, A=2. That is, when we call the add_two() function, we are actually calling the inner() function with saved parent variables. It means that when the add() function is called, the inner() function is saved in working memory, ready to be called with those default values.

I think it means that the first line with add_two refers to add_two as a variable and the second line with add_two(7) refers to add_two as a function?
But when is add_twoas a function defined??

All my confusion is maybe due to my poor understanding of the partial module that was first mentionned in the introductory course of this part 7, functionnal programming Learn data science with Python and R projects.

The partial module takes in a function, and “freezes” any number of args (or kwargs), starting from the first argument, then returns a new function with the default inputs.

I don’t think I understand what " returns a new function with the default inputs " actually means :thinking:.
What are these " default inputs " mentionned? When are they even defined?

Could someone please help me understand how this works?

Thank you very much in advance, it’s greatly appreciated.

Your confusion isn’t due to the concept of partial functions. How this works, is a different question in its own right. Can you ask it in a separate topic, please?

Regarding. . .

def add(A):
   def inner(b):
       # Use `A` from the argument in 
       # the parent add() function.
       return A + b
   return inner

add_two = add(2)
print(add_two(7))

. . . I’ll try to explain it in my own way and we’ll take it from there.

At the highest level, we’re defining a function add. We can say at least two things about this function:

  • It takes in a parameter (A).
  • It returns a function, let’s call it inner.

Note that inner is a function in its own right, it being a function means that you can call it like you call any function. In this case, inner takes one parameter, b, so inner(b) is “legal” code.

Let’s repeat: add returns a function (inner) and, function that inner is, we can call it.

Let’s see what happens when we call add with 2 as an argument (add(2)).

Expand here for the details

We step into add's definition. So what we’re doing is creating a function called inner in this way:

def inner(b):
    return 2 + b

Questions for you:

  • Why 2?

  • If we weren’t inside the definition of add, what would be the output of the following code?

    def inner(b):
        return 2 + b 
    
    print(inner(5))
    

Remember what I said at the start: add returns a function. That function is inner and it behaves as we just saw.

When you assign add(2) to add_two, you’re assigning the function that is returned by calling add(2) to add_two. This function, in the definition of add, was called inner, but here we renamed it as add_two.

Just like in. . .

def useless_function():
    x = 17
    return x

y = useless_function()

. . . we use y instead of x after calling the function.

So add_two is just the function inner we investigated in the collapsing button above. It’s a function that adds 2 to its parameter.

Thus, when we run add_two(7), we get the result of inner(7) as investigated above, that is: 2 + 7.


Here’s a different take on this, without much explanation. I hope it’s helpful nonetheless.

A different way of writing the starting code would be:

def add(A):
    return lambda b: A + b
1 Like