Python Dispatcher Definitions In A Function
Solution 1:
The i
in return i**2
is bound to the namei
, not the valuei
.
Try this to create a new variable, bound to the appropriate value:
defdispatcher_create():
dispatcher = {}
for i inrange(5):
defsquare(i=i):
return i**2
dispatcher[i] = square
for j inrange(5):
print dispatcher[j]()
return dispatcher
dispatcher_create()
Solution 2:
No, redefining square()
every time is doing what you want, which you can check by printing the contents of dispatcher
: all the functions in it will have different id's as desired.
The problem is that you're creating a closure so when you call any of the functions stored in dispatcher
they are accessing the latest value of i
, rather than using the value that i
had when they were defined.
Robᵩ has shown one way around that, by passing i
as an arg to square()
; here's another way: using another closure which takes i
as an arg so it can preserve it for the squaring function it makes.
defdispatcher_create():
dispatcher = {}
defmake_square(j):
defsquare():
return j**2return square
for i inrange(5):
dispatcher[i] = make_square(i)
return dispatcher
dd = dispatcher_create()
print dd
for j inrange(5):
print dd[j]()
typical output
{0: <function square at 0xb73a0a3c>, 1: <function square at 0xb73a0dbc>, 2: <function square at 0xb73a0d84>, 3: <function square at 0xb73a5534>, 4: <function square at 0xb73a517c>}
0
1
4
9
16
Robᵩ's version is a little simpler, but this version has the advantage that the functions in dispatcher
have the desired argument signature, i.e., they take no argument, whereas Robᵩ's functions take a single argument with a default value that you can over-ride.
FWIW, you could use i
instead of j
as the parameter for make_square()
, since it's just a local variable to make_square()
. OTOH, using i
there shadows the i
in the outer scope, and I feel that using j
is slightly less confusing.
Solution 3:
I believe it has to do with scope. The i variable remains defined after the for cycle it is used in. If you print the value of i after the for cycle, you see it is 4. If you then call the functions in the next for cycle, the value of i that is in the current scope is used.
As for the solution, i think functools.partial would be a good choice.
from functools import partial
defdispatcher_create():
dispatcher = {}
for i inrange(5):
defsquare(value):
return value**2
dispatcher[i] = partial(square, i)
for j inrange(5):
print dispatcher[j]()
return dispatcher
Post a Comment for "Python Dispatcher Definitions In A Function"