[Python-ideas] Fwd: collections.Counter should implement fromkeys
Steven D'Aprano
steve at pearwood.info
Fri Jun 29 22:37:33 EDT 2018
On Fri, Jun 29, 2018 at 05:32:54PM -0700, Abe Dillon wrote:
> Sure, but in Hettinger's own words
> <https://www.youtube.com/watch?v=HTLu2DFOdTg&t=24m46s> "whenever you have a
> constructor war, everyone should get their wish". People that want a
> counting constructor have that,
> people that want the ability to initialize values don't have that.
*scratches head*
I can initalise a Counter just fine.
py> Counter({'a': 0, 'b': 0, 'ab': 2})
Counter({'ab': 2, 'a': 0, 'b': 0})
The supported API for setting initial values of a counter is to either
count the supplied keys:
Counter(['a', 'b', 'ab'])
or supply initial counts in a dict:
Counter({'a': 0, 'b': 0, 'ab': 2})
In the case where all the inital counts are zero, the obvious API is to
call the dict fromkeys method:
Counter(dict.fromkeys(['a', 'b', 'ab'], 0))
So what you're really asking for is a convenience method to bypass the
need to create a temporary dict first:
Counter.fromkeys(['a', 'b', 'ab'], 0)
Presumably the initial value will default to 0 rather than None, and
take any integer value.
I'm sympathetic to the idea of this as a convenience, but I don't think
its an obvious feature to have. Tim's point about duplicate keys is
valid. Should it raise an exception, silently swallow duplicates, or
count them?
The dict constructors, both the standard dict() and dict.fromkeys(),
silently swallow duplicates. As they should. But Counter() does not,
and should not.
There's a discrepency if Counter() doesn't and Counter.fromkeys() does,
and it requires a value judgement to decide whether that discrepency is
sufficiently unimportant.
[...]
> Technically, there is no constructor for counting by X, but if enough
> people really wanted that, I suppose a third constructor would be in order.
How about a fourth constructor? A fifth? A fiftith? How many
constructors is too many before the class becomes unwieldy?
Not every way you might count with a counter needs to be a constructor
method. You can always just count:
c = Counter()
for key in keys:
c[key] += X
I think you make a *reasonable* case for Counter.fromkeys to silently
ignore duplicates, as a convenience method for
Counter(dict.fromkeys(keys, 0)
but its not (in my opinion) a *compelling* argument. I think it comes
down to the taste of the designer.
You can always subclass it. Or even monkey-patch it.
py> def fromkeys(cls, seq, value=0):
... c = cls()
... for key in seq:
... c[key] = value
... return c
...
py> from collections import Counter
py> Counter.fromkeys = classmethod(fromkeys)
py> Counter.fromkeys(['a', 'b', 'ab', 'a', 'b', 'c'])
Counter({'a': 0, 'ab': 0, 'b': 0, 'c': 0})
(Subclassing is safer :-)
--
Steve
More information about the Python-ideas
mailing list