Skip to content

Cannot customize Counter type #4032

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
davidblewett opened this issue Sep 29, 2017 · 8 comments
Closed

Cannot customize Counter type #4032

davidblewett opened this issue Sep 29, 2017 · 8 comments

Comments

@davidblewett
Copy link

I had a situation where I wanted a collections.Counter that had string keys and Decimal values, but it appears that the current typing definition of it is set to Counter[str] with int values, and no way of specifying a different type for values.

import typing
from collections import Counter
from decimal import Decimal


def test(foo:str) -> typing.Counter[str, Decimal]:
    bar: typing.Counter[str, Decimal] = Counter({'foo': Decimal('5.0')})
    bar[foo] += Decimal('5.0')
    return bar

returns:

counter_test.py:6: error: "Counter" expects 1 type argument, but 2 given
counter_test.py:7: error: "Counter" expects 1 type argument, but 2 given
counter_test.py:7: error: Dict entry 0 has incompatible type "str": "Decimal"
counter_test.py:9: error: Incompatible types in assignment (expression has type "Decimal", target has type "int")

I tried various approaches using typing.NewType , but couldn't figure out a combination to create a definition that could override the existing one for typing.Counter.

@davidblewett
Copy link
Author

import typing
from collections import Counter
from decimal import Decimal

DecimalCounter = typing.NewType('DecimalCounter', Counter)


def test(foo:str) -> DecimalCounter:
    bar: DecimalCounter = Counter({'foo': Decimal('5.0')})
    bar[foo] += Decimal('5.0')
    return bar

returns:


counter_test.py:9: error: Incompatible types in assignment (expression has type Counter[str], variable has type "DecimalCounter")
counter_test.py:9: error: Dict entry 0 has incompatible type "str": "Decimal"
counter_test.py:10: error: Incompatible types in assignment (expression has type "Decimal", target has type "int")

@davidblewett
Copy link
Author

import typing
from collections import Counter
from decimal import Decimal

DecimalDict = typing.Dict[str, Decimal]


def test(foo:str) -> DecimalDict:
    bar: DecimalDict = Counter({'foo': Decimal('5.0')})
    bar[foo] += Decimal('5.0')
    return bar

returns:

counter_test.py:9: error: Incompatible types in assignment (expression has type Counter[str], variable has type Dict[str, Decimal])
counter_test.py:9: error: Dict entry 0 has incompatible type "str": "Decimal"

@elazarg
Copy link
Contributor

elazarg commented Sep 29, 2017

I don't think this is related to mypy or typing. You are asking for a different kind of Counter implementation; this issue should be filed elsewhere (maybe discussed in python-ideas mailing list).

What's wrong with simply using defaultdict?

@davidblewett
Copy link
Author

The behavior of Counter has been very useful with other types of values than int. The docs even say:

Note 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.

@elazarg
Copy link
Contributor

elazarg commented Sep 29, 2017

Your example does not require Counter.

Adding another type argument will complicate the common use case. Besides, what should be the second type? It can't safely be some unbounded T. It will require some dedicated protocol.

@gvanrossum
Copy link
Member

Either the stub needs to be extended to match the behavior of the actual implementation in the stdlib (I don't know, I've never used Counter myself). In that case, please file a PR with the typeshed project. Or this requires a change in the stdlib. In which case please take the discussion to bugs.python.org.

@ilevkivskyi
Copy link
Member

ilevkivskyi commented Sep 29, 2017

When SupportsInt will be made a protocol in typeshed, then typeshed can probably define Counter as deriving from Dict[T, SupportsInt] instead of Dict[T, int] (however we need to be careful with invariance, there may be some underwater stones).

@JelleZijlstra
Copy link
Member

I believe the last time I looked into this, I concluded that Counter isn't actually supposed to use other value types than int.

wrobell pushed a commit to wrobell/osmgeodb that referenced this issue Jul 27, 2019

Unverified

No user is associated with the committer email.
  required as the issue seems to be stuck in limbo, see
  python/mypy#4032
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants