[Python-ideas] collections.Counter should implement __mul__, __rmul__

Tim Peters tim.peters at gmail.com
Mon Apr 16 01:07:24 EDT 2018


[Peter Norvig]
> For most types that implement __add__, `x + x` is equal to `2 * x`.
>
> That is true for all numbers, list, tuple, str, timedelta, etc. -- but not
> for collections.Counter. I can add two Counters, but I can't multiply one
> by a scalar. That seems like an oversight.
>
> ...
> Here's an implementation:
>
>    def __mul__(self, scalar):
>        "Multiply each entry by a scalar."
>        result = Counter()
>        for key in self:
>            result[key] = self[key] * scalar
>        return result
>
>    def __rmul__(self, scalar):
>        "Multiply each entry by a scalar."
>        result = Counter()
>        for key in self:
>            result[key] = scalar * self[key]
>        return result

Adding Counter * integer doesn't bother me a bit, but the definition
of what that should compute isn't obvious.  In particular, that
implementation doesn't preserve that `x+x == 2*x` if x has any
negative values:

>>> x = Counter(a=-1)
>>> x
Counter({'a': -1})
>>> x+x
Counter()

It would be strange if x+x != 2*x, and if x*-1 != -x:

>>> y = Counter(a=1)
>>> y
Counter({'a': 1})
>>> -y
Counter()

Etc.

Then again, it's already the case that, e.g., x-y isn't always the
same as x + -y:

>>> x = Counter(a=1)
>>> y = Counter(a=2)
>>> x - y
Counter()
>>> x + -y
Counter({'a': 1})

So screw obvious formal identities ;-)

I'm not clear on why "+" and "-" discard keys with values <= 0 to
begin with.  For "-" it's natural enough viewing "-" as being multiset
difference, but for "+"?  That's just made up ;-)

In any case, despite the oddities, I think your implementation would
be least surprising overall (ignore the sign of the resulting values).
At least for Counters that actually make sense as multisets (have no
values <= 0), and for a positive integer multiplier `n > 0`, it does
preserve that `x*n` = `x + x + ... + x` (with  `n` instances of `x`).


More information about the Python-ideas mailing list