The name Counter
is defined both in collections
(as a class) and in typing
(as a generic type name). Unfortunately, they are slightly different. What is the recommended way of dealing with this?
Similarities and differences:
After from collections import Counter
,
Counter("foo")
to create a fresh Counter
object;dict
: issubclass(Counter, dict)
returns True
;Counter
, e.g. cnt: Counter[str] = Counter("foo")
raises TypeError: 'type' object is not subscriptable
(the type hint fails)After from typing import Counter
,
Counter("foo")
to create a fresh Counter
object (actually, somewhat to my surprise);dict
: issubclass(Counter, dict)
raises TypeError: issubclass() arg 1 must be a class
;Counter
, e.g. cnt: Counter[str] = Counter("foo")
.In many cases 1.1 and 2.1 are good enough, so the choice of import doesn't matter.
But it seems you cannot have both 1.3 and 2.2 work with a single import. Of the latter two, the type hint is more important than the subclass check.
If you want to write type hints, then from typing import Counter
suffices.
Though, I would find it clearer (and more in line with what is needed for some other types) if you write
from collections import Counter # to indicate that you want the implementation
from typing import Counter # to indicate that you want to write type hints
(Note that the order matters.)
What if you want to have it all? These are the options that I see:
from collections import Counter
import typing
and use typing.Counter
to achieve 1.3. Not nice, too wordy.
import collections
from typing import Counter
and use collections.Counter
to achieve 2.2 (if needed; I needed it in teaching).
from collections import Counter as counter
from typing import Counter
and use counter
to achieve 2.2.
from collections import Counter
from typing import Counter as Bag # or Multiset
and use Bag
(or Multiset
) in type hints. (But this is bound to be confusing.)
import collections as co # to access the class
from typing import Counter # to access constructor and provide type hints
and use
co.Counter
or Counter
as the constructorco.Counter
as the class, e.g. issubclass(co.Counter, dict)
Counter
in type hints, e.g. cnt: Counter[str]
Is it then also to be recommended to do
from typing import Deque
and use Deque
as constructor, rather than co.deque
? (I'd think/hope not.)
For other types (such as defaultdict
and deque
) this does not seem to be an issue:
from collections import defaultdict, deque
from typing import DefaultDict, Deque
gives you all.
Am I overlooking something?
class collections. Counter ([iterable-or-mapping]) A Counter is a dict subclass for counting hashable objects. It is a collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts.
Counter is a subclass of dict that's specially designed for counting hashable objects in Python. It's a dictionary that stores objects as keys and counts as values. To count with Counter , you typically provide a sequence or iterable of hashable objects as an argument to the class's constructor.
Accessing Elements in Python Counter To get the list of elements in the counter we can use the elements() method. It returns an iterator object for the values in the Counter.
A counter can be used on a string, list, dictionary, and tuple.
Starting with Python 3.9 you can do:
from collections import Counter
c: Counter[str] = Counter()
See: https://docs.python.org/3/library/typing.html#typing.Counter
Deprecated since version 3.9: collections.Counter now supports []. See PEP 585 and Generic Alias Type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With