The use cases these TypeErrors would exclude include weightings (whether from a generator without an intermediate tuple/list or from a dict) where the need is to do elementwise multiplication:<div><br></div><div>if len(self) != len(other):</div><div>    raise ValueError("tensors are multiplicable")</div><div>if self.keys() != other.keys():</div><div>   #odict</div><div>if set(self.keys()).difference(other.keys()):</div><div>   # is this contract</div><div>   # is it this function's responsibility to check it</div><div>for (k1, v1), (k2, v2) in zip(self.items(), other.items()):</div><div>   self[k1] = v1*v2</div><div><br></div><div>At which point we might as well just introduce a sparse labeled array type that's interface-compatible with np.array and/or pd.Series(index=)</div><div>with a @classmethod Counter initializer that works like collections.Counter. (see links above)<br><br>On Wednesday, April 18, 2018, Tim Peters <<a href="mailto:tim.peters@gmail.com">tim.peters@gmail.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">[Raymond]<br>
>> I've started working on an implementation and several choices arise:<br>
>><br>
>> 1) Reject scalar with a TypeError if scalar is a Counter<br>
>> 2) Reject scalar with a TypeError if scalar is a Mapping<br>
>> 3) Reject scalar with a TypeError if scalar is a Collection<br>
>> 4) Reject scalar with a TypeError if scalar is Sized (has a __len__<br>
>> method).<br>
<br>
[Petr Viktorin <<a href="mailto:encukou@gmail.com">encukou@gmail.com</a>>]<br>
> Why is Iterable (__iter__) not on the list?<br>
><br>
> (Apologies if I missed this somewhere in the conversation.)<br>
<br>
I believe Raymond implicitly meant "test one of the above", not "test<br>
all of the above", and he's leaning toward Sized alone.<br>
<br>
What we're trying to stop is things like "Counter * Counter" for now,<br>
because the obvious implementation(*) of Counter.__mul__ would do a<br>
strange thing with that, where a quite different thing is plausibly<br>
wanted (and may - or may not - be added later - but, due to backward<br>
compatibility, cannot be added later if the initial implementation<br>
does the strange thing).<br>
<br>
Rejecting a Sized argument for now would stop that.  Piling on<br>
additional tests could stop other things "early", but every test added<br>
slows the normal case (the argument is fine).<br>
<br>
In the case of an Iterable `arg` that's not Sized, it seems highly<br>
unlikely that arg.__mul__ or arg.__rmul__ exist, so the obvious<br>
implementation would blow up later without bothering to check in<br>
advance:<br>
<br>
    >>> x = (i for i in range(10))<br>
    >>> 3 * x<br>
    Traceback (most recent call last):<br>
        ...<br>
    TypeError: unsupported operand type(s) for *: 'int' and 'generator'<br>
<br>
<br>
(*) The obvious implementation:<br>
<br>
    def __mul__(self, other):<br>
       if isinstance(other, Sized):<br>
           raise TypeError("cannot multiply Counter by Sized type %s"<br>
% type(other))<br>
        result = Counter()<br>
        for k, v in self.items():<br>
            result[k] = v * other<br>
        return result<br>
______________________________<wbr>_________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" target="_blank">https://mail.python.org/<wbr>mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" target="_blank">http://python.org/psf/<wbr>codeofconduct/</a><br>
</blockquote></div>