mypy cannot see through iterator dereference?

Created on 10 Aug 2018  路  6Comments  路  Source: python/mypy

Let me start with the example (Python 3.6, mypy 0.590):

set().union(*(x for x in [{1}, {2}, {3}]))
error: Argument 1 to "union" of "set" has incompatible type "*Iterator[Set[int]]"; expected "Iterable[<nothing>]"

In this case, I think the Set[int] should suffice for the Iterable[<nothing>], but mypy cannot see through the iterator dereference. I'm not entirely sure if this is a bug in mypy, or my understanding of its type system, which is why the subject is written as a question. I don't have immediate access to a more recent version for testing, so I don't know if this has already been fixed; I tried searching for it.

bug false-positive priority-1-normal

All 6 comments

I believe this is because mypy can't tell the type of the set() result, and it confuses it?

Yes, it seems mypy is confused by the empty set constructor. It is strange to me that we don't require an annotation, but I suppose that is due to the failed inference. As a work around, you can do this:

from typing import Set
a: Set[Set[int]] = set()
a = a.union(x for x in [{1}, {2}, {3}])

which is a bit weird, but works.

set.union(*(x for x in ({1}, {2}, {3}))) works too.

Interestingly, set.union(*iterable_of_sets) works, but set.union(*iterable_of_lists) does not, but set().union(*iterable_of_lists) does. In my case, set.union(...) works because my sets come from dict.keys(), and so I'll happily switch to it as a workaround, but this may still be a bug.

set().union(*iterable_of_lists)

Few days ago I discovered discussed mypy error for such code. In this case, as you already mentioned, set().union can't be directly replaced by set.union but variant below works (without mypy warnings):

set.union(*(set(x) for x in iterable_of_lists))

I remember, that stopped using it after code profiling. Variant with set().union was more than 2 times faster.

The issue with set.union(*iterable) is that it fails if the iterable is empty, while set().union(*iterable) works. So it is not a drop-in replacement.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JukkaL picture JukkaL  路  30Comments

gvanrossum picture gvanrossum  路  26Comments

dmoisset picture dmoisset  路  49Comments

JukkaL picture JukkaL  路  27Comments

datnamer picture datnamer  路  49Comments