Closures

A Closure is a function object that remembers values in enclosing scopes even if they are not present in memory.

def outer_fun():
    msg = 'HI'
    
    def inner_fun():
        print(msg)
    return inner_fun
my_func = outer_fun()
my_func()
my_func()
my_func()
HI
HI
HI
msg = "changed"
my_func()
HI

This is kinda interesting because we're done with execution of our outer function but the inner function that we return still has access to that message variable that it's printing out so that's what a closure is so in simple terms.

A closure is an inner function that remembers and has access to variables in the local scope in which it was created even after the outer function has finished executing.

def outer_fun(msg):
    message = msg
    
    def inner_fun():
        print(message)
    return inner_fun
hi_func = outer_fun("Hi")
hello_func = outer_fun("Hello")
hi_func()
hello_func()
Hi
Hello

So, when we have print these, we can see that each of these functions remembers the value of their own message variable.

One way to remember this: A Closure closes over the free variables from their environment and in this case message would be that free variable.

Reference

Corey Schafer