问题
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 ?
回答1:
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.
来源:https://stackoverflow.com/questions/18108775/defaultdict-constant-factory-doesnt-behave-as-expected