How to use a specific data structure as default_factory for defaultdict?

I am currently using defaultdict of Counter to uniquely count several unpredictable values ​​for unpredictable keys:

 from collections import defaultdict, Counter d = defaultdict(Counter) d['x']['b'] += 1 d['x']['c'] += 1 print(d) 

This gives me the expected result:

 defaultdict(<class 'collections.Counter'>, {'x': Counter({'c': 1, 'b': 1})}) 

Now I need to expand the value structure in defaultdict and make it dict with two keys: previous Counter and str :

 mystruct = { 'counter': collections.Counter(), 'name': '' } 

Is it possible to use a specific data structure (e.g. above) as default_factory in defaultdict ? The expected result will be that for each non-existent key in defaultdict a new key will be created and the value initialized by the structure indicated above.

+6
source share
2 answers

You just need to define your default_factory as a function that returns the default dictionary:

 from collections import defaultdict, Counter d = defaultdict(lambda: {'counter': Counter(), 'name': ''}) d['x']['counter']['b'] += 1 d['x']['counter']['c'] += 1 print(d) 

If you are not familiar with lambdas, this is the same as:

 def my_factory(): aDict = {'counter': Counter(), 'name':''} return aDict d = defaultdict(my_factory) 
+8
source

An alternative solution to drootang's answer is to use a custom class:

 from collections import defaultdict, Counter class NamedCounter: def __init__(self, name = '', counter = None): self.counter = counter if counter else Counter() self.name = name def __repr__(self): return 'NamedCounter(name={}, counter={})'.format( repr(self.name), repr(self.counter)) d = defaultdict(NamedCounter) d['x'].counter['b'] += 1 d['x'].counter['b'] += 1 d['x'].name = 'X counter' print(d) 

defaultdict (<class __main __. NamedCounter at 0x19de808>, {'x': NamedCounter (name = 'X counter', counter = Counter ({'b': 2}))})

Alternatively, you can extend Counter to include the name in the counter itself:

 from collections import defaultdict, Counter class NamedCounter(Counter): def __init__(self, name = '', dict = None): super(Counter, self).__init__(dict if dict else {}) self.name = name def __repr__(self): return 'NamedCounter(name={}, dict={})'.format( repr(self.name), super(Counter, self).__repr__()) d = defaultdict(NamedCounter) d['x']['b'] += 1 d['x']['b'] += 1 d['x'].name = 'X counter' print(d) 

defaultdict (<class '__main __. NamedCounter'>, {'x': NamedCounter (name = 'X counter', dict = {'b': 2})})

+1
source

All Articles