'''
A closure is a child function that has preserved the state of the data in its
parent function's scope.
'''
'''
printer is the parent function. It takes in a parameter called msg, and prints that parameter.
However, it also contains a child function that has access to the msg parameter.
This function (named closure for example purposes) has a property called __closure__.
This property is a tuple of cells, each of which contains the memory address
(or reference) to all free variables within the function. When the parent function
is executed, it returns the closure function. When the closure function is executed,
it looks up the value of the parameter within the saved state, and executes the
function with that value.
'''
def printer(msg):
print(msg) # <-- first thing to be executed
def closure(): # <-- when this is called, the value of msg is looked up in __closure__
# print(closure) # <-- included this for experimental purposes; contains a reference to the function itself
print(msg)
return closure
a = printer('hi') # a contains the returned function closure
a() # execute the closure
# print(a.__closure__) # prints the contents of __closure__
'''
In my snippet called Closures - Late Binding, there is an explanation on one
of the pitfalls of closures: late binding.
'''