Skip to content Skip to sidebar Skip to footer

Python Dispatcher Definitions In A Function

I'm running into issues with Python dispatcher definitions changing each time I add a new function to the dispatcher. An example: def dispatcher_create(): dispatcher = {} f

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"