Python: The Dictionary Playbook
blog.amir.rachum.com
blog.amir.rachum.com
from collections import defaultdict
counter = defaultdict(int)
There is a difference though, because you have to count manually, i.e: for i in 'supercalifragilisticexpialidocius':
counter[i] += 1
Also, because defaultdict accepts any callable, you can have a dict of counters by doing: counters = defaultdict(lambda: defaultdict(int))
for word in ['apple', 'berry', 'grape']:
for letter in word:
counters[word][letter] += 1
This is not very obvious, so I don't use it a lot, but sometimes it's the most elegant solution. import collections
c = collections.Counter('supercalifragilisticexpialidocius')
print c
# Counter({'i': 7, 'a': 3, 'c': 3, 'l': 3, 's': 3, 'e': 2,
# 'p': 2, 'r': 2, 'u': 2, 'd': 1, 'g': 1, 'f': 1,
# 'o': 1, 't': 1, 'x': 1})
[1] http://docs.python.org/2.7/library/collections.html#collecti...I guess python leaves so many ways to do things that you tend to settle on some style quickly even if it's not the most efficient one.
When self learning new languages I still miss an efficient way to get all the idioms. However I think that in python it's not really that important, as long as you get stuff done - your code is still going to be quite readable.
setdefault is new to me, which is cool. Unfortunately I can only see one place to use it in my code and it would be inefficient [0]. Best stash it away for later use :)
[0] r = re_subs.setdefault(s, re.compile(s))
Thanks for the tip (I was posting half hoping someone would have a better solution). That's another 3 lines of code removed :)
#x and y are dictionaries
z = dict(x.items() + y.items())
It merges two dictionaries, giving precedence to the second (in Python 2 - Python 3 is a bit more nasty: http://stackoverflow.com/questions/38987/how-can-i-merge-uni...). z=dict(x)
z.update(y)
It's clear and concise, and it's obvious which one gets precedence, even if it's two lines. z = dict(x, **y)
if the keys of y are compatible with unpacking.Great practice for 2.7 that's probably quashed in 3.0. For large dicts, no need to create a giant set en route when iterating over keys, values, or both. Use "for k in d.iterkeys()", "for v in d.itervals", "for k,v in d.iteritems."
While I'm at it-- if you're ever finding yourself using a huge amount of awfully rigid objects from a single class, use __slots__ to allocate needed variables! Python will otherwise define the object's namespace in a dict (called __dict__) which allocates a whole kilobyte per object. Bad news if you have several hundred thousand... Guessing this is why Guido loves namedtuples so much for basic attributed storage.
Iterate over keys: "for k in d.keys()" ...over values: "for v in d.values()" ...over both: "for k, v in d.items()"
The original plan was to simply let .keys(), .values() and
.items() return an iterator, i.e. exactly what iterkeys(),
itervalues() and iteritems() return in Python 2.x.
However, the Java Collections Framework [1] suggests that
a better solution is possible: the methods return objects
with set behavior (for .keys() and .items()) or multiset
(== bag) behavior (for .values()) that do not contain
copies of the keys, values or items, but rather reference
the underlying dict and pull their values out of the dict
as needed.>>key in dct
is much better than
key in dct.keys()
Of course, that got me curios to find out if there is a magic method out there that takes advantage of keyword "in". Turns out __contains__ does that.
Always exciting to stumble upon new stuff in my favorite language.
[1] http://docs.python.org/2/library/stdtypes.html#dictionary-vi...
Views are lighter than a full copy of a list, yet behaves like a list (eg: supports `key in view`).
[edit] Also, this seems to be the relevant PEP:
var = {'a' : 'b' , 'c' : {'d' : 'f'}}
print var.get('c', {}).get('d') print var.get('DNE', {}).get('d')
dct[key] = dct.setdefault(key, 0) + 1myset = {x for x in "This is my stuff".split()}
mydict = {x:len(x) for x in "This is my stuff".split()}
The advantage of this syntax is that : unambiguously introduces a key: value pair, whereas (key, value) could also occur in a list comprehension (e.g., by accident).
(key, val) in data
works if data = {(1,2) : 3}Are you planning on doing similar posts about other parts of Python in the future?
group = dct.setdefault(key, [])
group.append(value)
be replaced with some equivalent of this Ruby snippet: (dict[key] ||= []) << value
?But of course if ``group`` is not used afterwards it can be inlined to
dct.setdefault(key, []).append(value)http://dacavtricks.wordpress.com/2011/05/23/python-default-v...
d = defaultdict(lambda: False)
or d = defaultdict(lambda: {'foo':set(), 'bar':False})
d['baz']['foo'].add(1)