Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "late binding closures" mean? [duplicate]

I have a back-ground of C++ and trying to learn some python.

Whilst i understand virtual functions for C++, I unfortunately do not understand what is meant by late binding of closures in python.

Link: https://gist.github.com/deemson/8efabf56d67623ead804 (no longer works)

Copy-pasted from a tutorial:

functions = []
for n in [1, 2, 3]:
    def func(x):
        return n*x
    functions.append(func)

# You would expect this to print [2, 4, 6]
print(
    'calling a list of bad closures and output is: {}'
    .format(str([function(2) for function in functions]))
)

What exactly is happening here? When the function is appended in to the list, what values does it have? Can someone please simplify this code for me to understand?

like image 782
Bobo Avatar asked Apr 06 '16 22:04

Bobo


2 Answers

Notice this, you can create functions on runtime, more or less like lambdas in c++. So basically you are iterating over a list, making n take values 1,2 and 3

for n in [1, 2, 3]:
    def func(x):
        return n*x

so, by each iteration you are building a function named func, with takes a value and multiplies it for n. By appending it to the functions list you will have this functions stored, so you can iterate over the list to call the functions.

[function(2) for function in functions]

By doing this you call each of the functions stored with the value 2, you would expect this to output [2, 4, 6] ([1*2, 2*2, 3*2]), but instead it returns [6, 6, 6], WHY?, thats becouse every function use n for its computation, so they are not really doing 1*x, 2*x and 3*x but actually n*x and since n is bonded in last time to 3 all functions are doing 3*2 wich becomes 6.

Play around with the python console to check it properly.

like image 140
Netwave Avatar answered Sep 19 '22 03:09

Netwave


In the language of C++, a pointer to the function is what's being appended to the list. After the for loop, functions contains pointers to three different functions (func(x) = n * x, func(x) = n * x and func(x) = n * x). Note the dependency on n. As n changes, so will the behavior of these functions, and they are all equivalent.

In the second part of the code, the pointers are extracted from the list and each of the three functions is evaluated with an argument of 2.

Here's a further example to clarify. Imagine we do this:

>>> functions
[<function func at 0x0239AA70>, <function func at 0x0239AAB0>, <function func at 0x0239AB30>]
>>> g = functions[2]
>>> g
<function func at 0x0239AB30>
>>> g(10)
20
>>> g(100)
200

What we're seeing in that first lines is that functions contains pointers to three different functions. The next line extracts the third pointer from the list (which refers to func(x) = n * x) and assigns it to g. Effectively, we have defined a function g(x) = n * x with this call. We can now evaluate g with arguments.

Note that since all functions depend on n, you could change n, and the behavior would change.

>>> n = 100
>>> g(10)
1000
like image 32
Christian Avatar answered Sep 18 '22 03:09

Christian