It's odd that with all the 'high-brow' datatype names such as dictionaries, tuples, and sets, they decided to call this one Counter instead of the obvious choice 'multiset' (or 'bag'); it supports set operations such as intersection, so it's more generally useful than just collecting top ten lists &c.
It's not meant as a replacement; views form the new implementation of the keys(), values(), and items() methods in Python 3. The have been made available in Python 2 as viewkeys() etc. As said, they have the advantage of providing set operations (e.g., intersection with the keys of another dictionary), and they are more efficient than keys() or iterkeys(), because they have less overhead.
Happened to me too, I always used 'for key in mydict: do_something(key, mydict[key])' instead of 'for key, value'
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.
My good friend, refactoring is sometimes good, but remember the ancient wisdom: don't fix what's not broken! Your old code may not be pythonic, but still it works...
This is a really nice guide. I've been up to my eyes in python dicts over the last few days so already had most of these figured out.
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 :)
iirc re caches regexps. so unless you're using many (more than the cache size [edit: 100]), i wouldn't worry (well, and also measuring before optimising...)
I did wonder if that was the case but I couldn't find anything about it. Just discovered re._MAXCACHE which implies it does cache. Tested and in my case the performance is the same.
Thanks for the tip (I was posting half hoping someone would have a better solution). That's another 3 lines of code removed :)
In most circumstances for (key, val) in data won't work, as the default dictionary iterable only contains the keys. You want for key, val in data.items():
I use dictionary comprehensions personally but I have mixed feelings about the syntax. It looks too much like set comprehensions on first glance. Compare the following to see what I mean.
myset = {x for x in "This is my stuff".split()}
mydict = {x:len(x) for x in "This is my stuff".split()}
Well I see what you mean but then again a comma looks very much like a period ...
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).
Love defaultdict. It and dict/set/list compressions are a big part of what makes Python so fast to write in.
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.
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.
"for k in d" is even shorter. I wonder what they point of the .keys() method is actually, perhaps it's just as redundant as .has_key(). Most times you can iterate over the dictionary itself; when you need to explicitly pass an iterator or list, iter(d) or list(d) is shorter than d.keys().
Only in Python 2, which returns something to the effect of list(dict); so my point remains, they keys method doesn't add anything which you don't get (more explicitly) by coercing to a list when needed.
58 comments
[ 3.0 ms ] story [ 122 ms ] thread[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:
http://www.python.org/dev/peps/pep-3106/
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 :)
Are you planning on doing similar posts about other parts of Python in the future?
myset = {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 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.
var = {'a' : 'b' , 'c' : {'d' : 'f'}}
print var.get('c', {}).get('d') print var.get('DNE', {}).get('d')
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()"
http://dacavtricks.wordpress.com/2011/05/23/python-default-v...
But of course if ``group`` is not used afterwards it can be inlined to