typeshed
typeshed copied to clipboard
Counter() support non-int
I'm quite surprised because I can use a Counter to store non-integer values. Is it a feature or just permissiveness in implementation?
E.g. the following code works (tested on python 3.7.4):
from collections import Counter
spam = Counter()
spam["egg"] += 3.4
While the Counter implementation accepts non-int values, I would be careful to use them. Nothing in the documentation suggests that non-int values are okay to use, and Counter could break in subtle ways now or in the future. As such I believe it is safer not to change the annotations in typeshed to be more permissive.
Actually I overlooked the big box which says:
Counters were primarily designed to work with positive integers to represent running counts; however, care was taken to not unnecessarily preclude use cases needing other types or negative values. To help with those use cases, this section documents the minimum range and type restrictions. [...]
PRs to improve Counter welcome!
Some previous discussion in python/mypy#4032
Hi, I arrived here from https://github.com/python/mypy/issues/4032. I'm trying to use Counter with floats, and mypy gives me Incompatible types in assignment since it expects ints.
Are we in a discussion about whether the standard library's Counter was ever meant to be used with non-integers (the answer is not obvious to me) or we need to update Counter in collections.pyi to support non-integers (for example, like suggested https://github.com/python/mypy/issues/4032#issuecomment-333158323)
Note that changes to Counter typing may break existing annotations. There will likely be a tradeoff between allowing more flexibility and retaining compatibility with existing annotations.
This is a good example, where defaults for type vars (python/typing#307) would come in handy.
Have there been any changes in this or any suggested work-arounds? I'm using Counter with floats and need Counter.total(). Something like defaultdict won't help: "defaultdict[str, float]" has no attribute "total"
Have there been any changes in this or any suggested work-arounds?
Feel free to file a PR to see what mypy_primer says in our CI, but as Jukka says, I think it's likely that changing the stubs for Counter at this point would break a lot of existing type annotations. So there's probably not much we can do here.
I'm using
Counterwithfloatsand needCounter.total(). Something likedefaultdictwon't help:"defaultdict[str, float]" has no attribute "total"
You could just use Counter anyway, and type: ignore the errors away. But the runtime implementation for Counter.total() is actually extremely simple, so another option would be to just subclass defaultdict and add your own total() method:
class DefaultDictWithTotal(defaultdict):
def total(self) -> float:
'Sum of the counts'
return sum(self.values())
Thanks.
FWIW, in order to pass mypy --strict I had to add 2 arguments:
class DefaultDictWithTotal(defaultdict[Any, Any]):
def total(self) -> float:
'Sum of the counts'
return sum(self.values())
and then to use it: whatever = DefaultDictWithTotal(float)
I marked this as deferred for now, pending the implementation of type var defaults.
See #11422 for the type var generics feature tracker.
Type var defaults are now available.