Open manu3618 opened 4 years ago
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 float
s, and mypy
gives me Incompatible types in assignment
since it expects int
s.
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
Counter
withfloats
and needCounter.total()
. Something likedefaultdict
won'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.
@srittau I also opened up a PR for this, that I think covers some of the additional edge cases that weren't covered, but happy to close it if you prefer to simply implement them, or if you want to take a look.
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):