| Sam ( @ 2008-01-16 17:23:00 |
| Current mood: | |
| Entry tags: | programming |
Python Counters and Accumulators
Another post while [gigantic test script] runs (so I can continuer debugging SQL weirdness). Probably worth reading if and only if you're a Python programmer:
So, I just recently discovered the setdefualt function of dict (because I'm slow). Basically, it allows you to replace the common task (given foo = {}):
if not foo.has_key('bar'):
foo['bar'] = []
foo['bar'].append('baz')With:foo.setdefault('bar',[]).append('baz')This works for sets, too, just replace [] with set() and append with add. On the other hand, this doesn't work with counters (which could be viewed as integer accumulators):foo.setdefault('bar',0) += 1For that, you have to use a different idiom:foo['bar'] = foo.get('bar',0) + 1Note that this idiom won't work with sets or lists, since add and append return None instead of a self-reference (this may be an argument why certain python methods should return self instead of None, but that's a whole different topic).Anyways, this whole thing amounts to a minor point of interest, except I sort of would like to use the same idiom for counters and object-based accumulators. It just seems to me that if the first line below works, the second line should too:
foo['bar'] += 1
foo.setdefault('bar',0) += 1P.S. The collections.defaultdict solves this problem in a pretty smooth way. Note that it takes a function, not a constant, as a parameter:from collections import defaultdict
foo = defaultdict(0) # Doesn't work: TypeError
foo = defaultdict(lambda: 0) # Works as expected.. but somewhat ugly
foo = defaultdict(int) # Nicer, works as expected (int() == 0)
foo['bar'] += 1
foo = defaultdict(list) # Likewise for this
foo['bar'].append('baz')
foo = defaultdict(set) # And this
foo['bar'].add('baz')