[Python-ideas] collections.Counter should implement __mul__, __rmul__
Steve Barnes
gadgetsteve at live.co.uk
Mon Apr 16 01:22:54 EDT 2018
On 16/04/2018 06:07, Tim Peters wrote:
> [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`).
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
Wouldn't it make sense to have the current counter behaviour, (negative
counts not allowed), and also a counter that did allow negative values
(my bank doesn't seem to have a problem with my balance being able to go
below negative), and possibly at the same time a counter class that
allowed fractional counts?
Then:
>>>> x = Counter(a=1)
>>>> y = Counter(a=2)
>>>> x - y
> Counter()
>>>> x + -y
> Counter({'a': 1})
BUT:
>>>> x = Counter(a=1, allow_negative=True)
>>>> y = Counter(a=2, allow_negative=True)
>>>> x - y
> Counter({'a': 1})
>>>> x + -y
> Counter({'a': 1})
Likewise for a Counter that was allowed to be fractional the result of
some_counter / scalar would have (potentially) fractional results and
one that did not would give floor results.
--
Steve (Gadget) Barnes
Any opinions in this message are my personal opinions and do not reflect
those of my employer.
---
This email has been checked for viruses by AVG.
http://www.avg.com
More information about the Python-ideas
mailing list