in this code:
results = []
for i in [1, 2, 3, 4]:
def inner(y):
return i
results.append(inner)
for i in results:
print i(None)
the output is "function inner at 0x107dea668"
if i change i to other letter, for example:
results = []
for i in [1, 2, 3, 4]:
def inner(y):
return i
results.append(inner)
for j in results:
print j(None)
the output is "4"
Answer
results = []
for i in [1, 2, 3, 4]:
def inner(y):
print "in inner:%s " % id(i)
return i
results.append(inner)
# i -> 4
for i in results:
# i -> func inner
print "i: %s" % i
print "in loop: %s " % id(i)
# func inner <===> A
# i == A -> return i -> return A, so when call funtion inner, will return itself
# print "call: %s" % i(None)
print "call: %s" % i(None)(None)(None)
print "------------------------------"
i: function inner at 0x101344d70
in loop: 4315172208
in inner:4315172208
in inner:4315172208
in inner:4315172208
call: function inner at 0x101344d70
i: function inner at 0x101344de8
in loop: 4315172328
in inner:4315172328
in inner:4315172328
in inner:4315172328
call: function inner at 0x101344de8
i: function inner at 0x101344e60
in loop: 4315172448
in inner:4315172448
in inner:4315172448
in inner:4315172448
call: function inner at 0x101344e60
i: function inner at 0x101344ed8
in loop: 4315172568
in inner:4315172568
in inner:4315172568
in inner:4315172568
call: function inner at 0x101344ed8
The inner
function you have defined contains a free variable referring to the global variable i
. This is perhaps clearer in an example like this:
def inner(y):
return i
i = 1
print inner(None)
i = 2
print inner(None)
which prints 1 and then 2
In your first example, at the time of the call to inner
, i
has the value which is the function and so that is what is printed when i
(which is inner
) is called.
In the second example, at the time of the call to inner
, i
has the value 4 and so that is what is printed when j
(which is inner
) is called.
A clear way to express what you presumably wanted here is to use a partially evaluated function, as recommended in another answer. Another way is to use an enclosing function to create a closure. Like this:
results = []
for i in [1, 2, 3, 4]:
def outer(k):
def inner(y):
return k
return inner
results.append(outer(i))
for i in results:
print i(None)
which will print 1 to 4 as presumably you want.
A little trick sometimes used in Python is to use the default value of a variable as a cell to contain a value:
results = []
for i in [1, 2, 3, 4]:
def inner(y, i = i):
return i
results.append(inner)
for i in results:
print i(None)
which also prints 1 to 4.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With