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

Tim Peters tim.peters at gmail.com
Wed Apr 18 14:45:59 EDT 2018


[Raymond]
>> I've started working on an implementation and several choices arise:
>>
>> 1) Reject scalar with a TypeError if scalar is a Counter
>> 2) Reject scalar with a TypeError if scalar is a Mapping
>> 3) Reject scalar with a TypeError if scalar is a Collection
>> 4) Reject scalar with a TypeError if scalar is Sized (has a __len__
>> method).

[Petr Viktorin <encukou at gmail.com>]
> Why is Iterable (__iter__) not on the list?
>
> (Apologies if I missed this somewhere in the conversation.)

I believe Raymond implicitly meant "test one of the above", not "test
all of the above", and he's leaning toward Sized alone.

What we're trying to stop is things like "Counter * Counter" for now,
because the obvious implementation(*) of Counter.__mul__ would do a
strange thing with that, where a quite different thing is plausibly
wanted (and may - or may not - be added later - but, due to backward
compatibility, cannot be added later if the initial implementation
does the strange thing).

Rejecting a Sized argument for now would stop that.  Piling on
additional tests could stop other things "early", but every test added
slows the normal case (the argument is fine).

In the case of an Iterable `arg` that's not Sized, it seems highly
unlikely that arg.__mul__ or arg.__rmul__ exist, so the obvious
implementation would blow up later without bothering to check in
advance:

    >>> x = (i for i in range(10))
    >>> 3 * x
    Traceback (most recent call last):
        ...
    TypeError: unsupported operand type(s) for *: 'int' and 'generator'


(*) The obvious implementation:

    def __mul__(self, other):
       if isinstance(other, Sized):
           raise TypeError("cannot multiply Counter by Sized type %s"
% type(other))
        result = Counter()
        for k, v in self.items():
            result[k] = v * other
        return result


More information about the Python-ideas mailing list