Question

I'm willing to use defaultdict with an ad hoc default_factory which suits better my purpose. The default_factory would be [0,0].

I've implemented a constant_factory function:

def constant_factory(value):
    return itertools.repeat(value).next

Then when I try to use it, my defaultdict has an unexpected behavior (at least a behavior I didn't expect).

Here is an example:

>>>import itertools
>>>from collections import defaultdict
>>>dictio=defaultdict(constant_factory([0,0]))
>>>for i in xrange(10):
...    dictio[i][0]+=1
>>>dictio
defaultdict(<method-wrapper 'next' of itertools.repeat object at 0x000000000355FC50>, {0: [10, 0], 1: [10, 0], 2: [10, 0], 3: [10, 0], 4: [10, 0], 5: [10, 0], 6: [10, 0], 7: [10, 0], 8: [10, 0], 9: [10, 0]})

Instead I'd like to get: defaultdict(<method-wrapper 'next' of itertools.repeat object at 0x000000000355FC50>, {0: [1, 0], 1: [1, 0], 2: [1, 0], 3: [1, 0], 4: [1, 0], 5: [1, 0], 6: [1, 0], 7: [1, 0], 8: [1, 0], 9: [1, 0]})

It seems that, each time I'm willing to increment the value of the first slot of the list corresponding to the key i, it increments all the values of the the first slots.

Since I'm pretty new to using defaultdict and method wrapper can anybody explain me what I am doing wrong since I believe Python is doing its work perfectly well ?

Was it helpful?

Solution

First of all, just use:

defaultdict(lambda: [0, 0])

Your rather elaborate callable returns the same list over and over again. You are using the same list for all values in your dictionary. The above lambda returns a new list each time it is called instead:

>>> import itertools
>>> lambda_default = lambda: [0, 0]
>>> iter_default = itertools.repeat([0, 0]).next
>>> lambda_default() is lambda_default()
False
>>> iter_default() is iter_default()
True

You thus fill your dictionary with references to one list, and altering values in that one list is reflected everywhere the reference to that one list is printed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top