What's happening is the same as this:
>>> a = 5
>>> def foo(): print(a)
>>> foo()
5
>>> a = 10
>>> foo()
10
>>> a = 'fred'
>>> foo()
fred
And also the same as this:
>>> def bar(): return b
>>> bar()
Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
bar()
File "<pyshell#29>", line 1, in bar
def bar(): return b
NameError: global name 'b' is not defined
>>> b = 3
>>> bar()
3
The variables you used inside a function aren't resolved until the function is called not when it is written. There's some magic, called closures, that means functions defined inside other functions (as your update
functions are defined inside func
) still have access to all the variables defined in the outer function - but they still don't actually get resolved until the function is called. So, by the time each of your update
functions is called, i
is 9.
Using default argument values, as in @gnibbler's answer, works because the i
that each update
looks up will resolve to the argument (which shadows the outer variable). Those won't change, because default argument values are evaluated when the function is defined (which also leads to the mutable defaults bug that a lot of people run into sooner or later).