[Python-checkins] r68562 - in python/trunk: Doc/library/collections.rst Lib/collections.py Lib/test/test_collections.py
raymond.hettinger
python-checkins at python.org
Tue Jan 13 02:05:04 CET 2009
Author: raymond.hettinger
Date: Tue Jan 13 02:05:03 2009
New Revision: 68562
Log:
Simplify Counter() API. Replace items keyword argument
with a mapping. Makes Counter() idempotent, makes update()
API the same as Counter.__init__(), makes a more readable
repr, makes the API more dict-like, and allows Steven
Bethard's update() example to work.
Modified:
python/trunk/Doc/library/collections.rst
python/trunk/Lib/collections.py
python/trunk/Lib/test/test_collections.py
Modified: python/trunk/Doc/library/collections.rst
==============================================================================
--- python/trunk/Doc/library/collections.rst (original)
+++ python/trunk/Doc/library/collections.rst Tue Jan 13 02:05:03 2009
@@ -161,12 +161,12 @@
For example::
# Tally repeated words in a list
- >>> words = ['red', 'blue', 'red', 'green', 'blue', blue']
+ >>> words = ['red', 'blue', 'red', 'green', 'blue', 'blue']
>>> cnt = Counter()
>>> for word in words:
... cnt[word] += 1
>>> cnt
- Counter(items=[('blue', 3), ('red', 2), ('green', 1)])
+ Counter({'blue': 3, 'red': 2, 'green': 1})
# Find the ten most common words in Hamlet
>>> import re
@@ -175,21 +175,20 @@
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
-.. class:: Counter([iterable[, items]])
+.. class:: Counter([iterable])
A :class:`Counter` is a :class:`dict` subclass for counting hashable items.
- Elements are stored as dictionary keys and their counts are stored as
- dictionary values. Counts are allowed to be any integer value including
- zero or negative counts. The :class:`Counter` class is similar to bags
- or multisets in other languages.
+ It is an unordered collection where elements are stored as dictionary keys
+ and their counts are stored as dictionary values. Counts are allowed to be
+ any integer value including zero or negative counts. The :class:`Counter`
+ class is similar to bags or multisets in other languages.
Elements are counted from the *iterable* if given. Also, the counts
- can be initialized from an *items* list of *(element, count)* pairs.
- If provided, *items* must be a keyword argument::
+ can be initialized from another mapping of elements to their counts::
>>> c = Counter() # a new, empty counter
>>> c = Counter('gallahad') # a new counter from an iterable
- >>> c = Counter(items=[('a', 4), ('b', 2)]) # a new counter from an items list
+ >>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping
The returned object has a dictionary style interface except that it returns
a zero count for missing items (instead of raising a :exc:`KeyError` like a
@@ -222,7 +221,7 @@
Elements are returned in arbitrary order. If an element's count has been
set to zero or a negative number, :meth:`elements` will ignore it.
- >>> c = Counter(items=[('a', 4), ('b', 2), ('d', 0), ('e', -2)])
+ >>> c = Counter({'a': 4, 'b': 2, 'd': 0, 'e': -2})
>>> list(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
@@ -245,19 +244,20 @@
There is no equivalent class method for :class:`Counter` objects.
Raises a :exc:`NotImplementedError` when called.
- .. method:: update(mapping)
+ .. method:: update(iterable)
Like :meth:`dict.update` but adds-in counts instead of replacing them.
- Used for combining two independent counts. Accepts a *mapping* object
- which can be another counter or can be a :class:`dict` that maps
- elements to element counts::
+
+ Elements are counted from the *iterable* if given. Also, the counts
+ can be taken from another counter or mapping of elements to their
+ counts::
>>> c = Counter('which') # count letters in a word
>>> d = Counter('witch') # count letters in another word
>>> c.update(d) # add counts from d to those in c
>>> c['h'] # count of 'h' is now three
3
- >>> c.update(Counter('watch')) # add in letters from another word
+ >>> c.update('watch') # add in letters from another word
>>> c['h'] # count of 'h' is now four
4
Modified: python/trunk/Lib/collections.py
==============================================================================
--- python/trunk/Lib/collections.py (original)
+++ python/trunk/Lib/collections.py Tue Jan 13 02:05:03 2009
@@ -167,21 +167,17 @@
# http://code.activestate.com/recipes/259174/
# Knuth, TAOCP Vol. II section 4.6.3
- def __init__(self, iterable=None, items=None):
+ def __init__(self, iterable=None):
'''Create a new, empty Counter object. And if given, count elements
- from an input iterable. Or, initialize the count from an items list
- of (element, count) pairs.
+ from an input iterable. Or, initialize the count from another mapping
+ of elements to their counts.
- >>> c = Counter('hocus pocus') # count elements in an iterable
- >>> c = Counter(items=[('a', 4), ('b', 2)]) # take counts from an items list
+ >>> c = Counter() # a new, empty counter
+ >>> c = Counter('hocus pocus') # a new counter from an iterable
+ >>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping
'''
- if iterable is not None:
- for elem in iterable:
- self[elem] += 1
- if items is not None:
- for elem, count in items:
- self[elem] += count
+ self.update(iterable)
def __missing__(self, key):
'The count of elements not in the Counter is zero.'
@@ -210,7 +206,7 @@
# Knuth's example of prime factors of 1836: 2**2 * 3**3 * 17**1
>>> import operator
- >>> prime_factors = Counter(items=[(2,2), (3,3), (17,1)])
+ >>> prime_factors = Counter(dict([(2,2), (3,3), (17,1)]))
>>> sorted(prime_factors.elements()) # list individual factors
[2, 2, 3, 3, 3, 17]
>>> reduce(operator.mul, prime_factors.elements(), 1) # multiply them
@@ -234,16 +230,19 @@
raise NotImplementedError(
'Counter.fromkeys() is undefined. Use Counter(iterable) instead.')
- def update(self, mapping):
+ def update(self, iterable=None):
'''Like dict.update() but add counts instead of replacing them.
- Source can be another dictionary or a Counter.instance().
+ Source can be an iterable, a dictionary, or another Counter.instance().
>>> c = Counter('which')
>>> d = Counter('witch')
- >>> c.update(d) # Add counts from d to those in c
- >>> c['h'] # Count of 'h' is now three
+ >>> c.update(d) # add counts from d to those in c
+ >>> c['h'] # count of 'h' is now three
3
+ >>> c.update('watch')
+ >>> c['h']
+ 4
'''
# The regular dict.update() operation makes no sense here because the
@@ -254,19 +253,24 @@
# multisets and implement the union-add operation discussed in
# TAOCP Volume II section 4.6.3 exercise 19. The Wikipedia entry for
# multisets calls that operation a sum or join.
- for elem, count in mapping.iteritems():
- self[elem] += count
+
+ if iterable is not None:
+ if isinstance(iterable, Mapping):
+ for elem, count in iterable.iteritems():
+ self[elem] += count
+ else:
+ for elem in iterable:
+ self[elem] += 1
def copy(self):
'Like dict.copy() but returns a Counter instance instead of a dict.'
- c = Counter()
- c.update(self)
- return c
+ return Counter(self)
def __repr__(self):
if not self:
return '%s()' % self.__class__.__name__
- return '%s(items=%r)' % (self.__class__.__name__, self.most_common())
+ items = ', '.join('%r: %r' % item for item in self.most_common())
+ return '%s({%s})' % (self.__class__.__name__, items)
Modified: python/trunk/Lib/test/test_collections.py
==============================================================================
--- python/trunk/Lib/test/test_collections.py (original)
+++ python/trunk/Lib/test/test_collections.py Tue Jan 13 02:05:03 2009
@@ -370,8 +370,7 @@
self.assertEqual(c.get('b', 10), 2)
self.assertEqual(c.get('z', 10), 10)
self.assertEqual(c, dict(a=3, b=2, c=1))
- self.assertEqual(repr(c),
- "Counter(items=[('a', 3), ('b', 2), ('c', 1)])")
+ self.assertEqual(repr(c), "Counter({'a': 3, 'b': 2, 'c': 1})")
self.assertEqual(c.most_common(), [('a', 3), ('b', 2), ('c', 1)])
for i in range(5):
self.assertEqual(c.most_common(i),
@@ -396,8 +395,8 @@
self.assertRaises(NotImplementedError, Counter.fromkeys, 'abc')
self.assertRaises(TypeError, hash, c)
c.update(dict(a=5, b=3, c=1))
- c.update(Counter(items=[('a', 50), ('b', 30)]))
- c.__init__(items=[('a', 500), ('b', 300)])
+ c.update(Counter('a' * 50 + 'b' * 30))
+ c.__init__('a' * 500 + 'b' * 300)
c.__init__('cdc')
self.assertEqual(c, dict(a=555, b=333, c=3, d=1))
self.assertEqual(c.setdefault('d', 5), 1)
@@ -425,6 +424,7 @@
cPickle.loads(cPickle.dumps(words, -1)),
eval(repr(words)),
update_test,
+ Counter(words),
]):
msg = (i, dup, words)
self.assert_(dup is not words)
More information about the Python-checkins
mailing list