21

I am trying to annotate my code with types but I am a little confused when it comes to sets. I read some points in PEP 484:

Note: Dict , List , Set and FrozenSet are mainly useful for annotating return values. For arguments, prefer the abstract collection types defined below, e.g. Mapping , Sequence or AbstractSet .

and

Set, renamed to AbstractSet . This name change was required because Set in the typing module means set() with generics.

but this does not help.

My first question is: what are the commonalities and differences between Set, FrozenSet, MutableSet and AbstractSet?

My second question is: why if I try

from collections import FrozenSet

I get

ImportError: cannot import name 'FrozenSet'

?

I am using Python 3.4 and I have installed mypy-lang via pip.

max
  • 49,282
  • 56
  • 208
  • 355
marcotama
  • 1,991
  • 2
  • 19
  • 24

5 Answers5

7

Be careful with annotations and typing. The ideas discussed in 484 are brand new, and implemented in the typing module. That module is only available in Python3.5 (the latest typing is also available from pip for both Py2 and Py3).

https://docs.python.org/3/library/typing.html

That note that you quoted is from a section in 484 that starts:

To open the usage of static type checking to Python 3.5 as well as older versions, a uniform namespace is required. For this purpose, a new module in the standard library is introduced called typing .

The things that the note lists are annotation types, not actual object classes (builtin or from collections). Don't confuse the two.

Note that Dict , List , Set and FrozenSet are all capitalized, where as the functions (and type names) are dict, list, set, frozenset. In other words to make a dictionary you use dict() or {}, not Dict.

Annotations are new to 3.0 (not in 2.n at all). In a regular interpreter all they do is populate the function's __annotations__ dictionary. There's nothing in the interpreter that uses or requires annotations.

http://mypy-lang.org/ describes itself as an experiemental typing checker. You need to look at it's documentation to see how compatible it is with 484 etc.

https://docs.python.org/3/library/collections.abc.html#module-collections.abc has some abstract definitions, which I believe typing uses. I've never used these. They are mainly for people developing new classes of objects, not 'regular' users.

The typing tag for this question is probably not a good idea. It doesn't have many followers, and is too generic. It does not refer to this Python module.

Search for [python] 484 for other SO questions dealing with this style of annotations.

https://github.com/python/typing - the typing development repository.

In this repository, there is a FrozenSet definition in the python2/typing.py file (the python2 backport), but not in src/typing.py. I'm not sure of the significance of that.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Hi, thanks for your reply. I have clearer ideas now (I knew about the difference between annotation types and objects, but did not know about mypy's typing vs python3.5's typing modules). However, I looked into both documentations and could not find a reference to FrozenSet, which was mentioned in PEP 484. Am I missing something? – marcotama Mar 10 '16 at 05:17
  • Looks like they haven't added `FrozenSet` to `typing`. Many of the classes in `typing` map on to `collections.abc`, which has things like `MutableSet` and `AbstractSet`, but not `FrozenSet`. So at this point `FrozenSet` is just an idea in the PEP, nothing more. – hpaulj Mar 10 '16 at 05:26
  • There's a github repository for the `typing` module. Explore that to see what might be added in the future. – hpaulj Mar 10 '16 at 05:31
  • Looks like `typing` and `mypy` have to be used together. Use the features that both implement, and forget about extras in the PEP. And expect things to change, since both are under development. – hpaulj Mar 10 '16 at 06:13
  • Thanks for clarifying. I removed the tag typing - I agree it was not a good idea (python-typing would have been better, but does not exist). – marcotama Mar 10 '16 at 06:29
  • Actually, FrozenSet is there also in `src/typing.py`. I will just need to use Python 3.5 apparently. Please verify and edit your answer. – marcotama Mar 10 '16 at 06:36
  • I was scanning the `github` source; but yes, it is in the 3.5 file. – hpaulj Mar 10 '16 at 07:00
4

Two years late to the party, but anyway...

You can think of AbstractSet and MutableSet as like an interface in Java or an abstract base class in Python. Python's builtin set() and frozenset() are one implementation, but someone could create another implementation that doesn't use the builtins at all.

FrozenSet and Set, on the other hand, represent the types of the concrete built in classes frozenset and set.

For example, the "interface" types don't have union methods, while the concrete types do. So:

def merge(a: Set[str], b: Iterable[str]) -> Set[str]:
    return a.union(b)

will type check just fine, but if you change the type of a to AbstractSet, mypy says:

typetest.py:7: error: "AbstractSet[str]" has no attribute "union"

Martin C. Martin
  • 3,565
  • 3
  • 29
  • 36
  • Why do [the docs](https://docs.python.org/3/library/typing.html#typing.Set) say that AbstractSet is preferred for typing parameters then? "To annotate arguments it is preferred to use an abstract collection type such as AbstractSet." – Pro Q Jun 03 '19 at 07:02
  • @ProQ It also does not work if you need `union` or `intersection`. I'm not sure why `AbstractSet` does not support these. – Alan Jun 15 '20 at 19:41
2

These type names are indeed a little confusing. There was a related discussion on mypy Gitter, and Guido provided a clarification.

typing.AbstractSet and typing.MutableSet are the types for ABCs (abstract base classes), not concrete implementations of the set type:

  • typing.AbstractSet is the type for collections.abc.Set, which is an ABC (abstract base class) for an immutable set.
  • typing.MutableSet is the type for collections.abc.MutableSet, which is an ABC for a mutable set.

typing.Set and typing.FrozenSet are the types for concrete set implementations, available in the stdlib:

  • typing.Set is the type for stdlib set, which is a concrete implementation of a mutable set.
  • typing.FrozenSet is the type for stdlib frozenset, which is a concrete implementation of an immutable set.
wombatonfire
  • 4,585
  • 28
  • 36
1

The set type is mutable -- the contents can be changed using methods like add() and remove(). Since it is mutable, it has no hash value and cannot be used as either a dictionary key or as an element of another set. The frozenset type is immutable and hashable -- its contents cannot be altered after is created; however, it can be used as a dictionary key or as an element of another set.

from: https://docs.python.org/3/library/stdtypes.html#frozenset

you don't need to include it, it's built in, you just do:

cities = frozenset(["Frankfurt", "Basel","Freiburg"])

tested in 3.4.2

Matt
  • 27,170
  • 6
  • 80
  • 74
lciamp
  • 675
  • 1
  • 9
  • 19
  • Thanks, I know these differences. The question was about how these types are mapped in the typing module. I am sorry if I was not clear. – marcotama Mar 10 '16 at 05:13
1

Update in Python 3.9+ (2021+)

The relationship between builtin set, collections.abc.Set, typing.Set, and typing.AbstractSet had a complicated history. Starting in Python 3.9, PEP 585 deprecated collections.abc.Set, typing.Set, and typing.AbstractSet and aliased them to the builtin set. Correspondingly, typing.FrozenSet was deprecated and aliased to the builtin frozenset.

TL; DR: Use only the builtin set and frozenset for typing.

In action:


from collections.abc import Iterable

# using Python 3.12+ generics
def union[T](a: Iterable[T], b: Iterable[T]) -> set[T] | frozenset[T]:
    if isinstance(a, frozenset) or isinstance(b, frozenset):
        return frozenset(a) | frozenset(b)
    return set(a) | set(b)

assert union({1}, {2}) == {1, 2}
assert union(frozenset({1}), {2}) == frozenset({1, 2})