You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I suspect this is some kind of co-/contra-variance issue, but I quite can't
put my finger on it. It looks like the type variables used to define Dict
are invariant. But I don't know if that's the whole picture (mypy
implements its own rules rather than using the definitions in typing.py).
The behavior is correct, as the second type parameter to Dict is invariant. However, if you'd use Mapping[str, Sequence[int]], this should work (but it doesn't).
To see why mypy complains about the code, consider this slightly different example:
from typing import Dict, Sequence
def f(data: Dict[str, Sequence[int]]) -> None:
data['x'] = (1, 2)
data = {"a": [1, 2]}
f(data)
data['x'].append(1) # error, tuple doesn't support append
If the value type parameter of Dict would be covariant, mypy wouldn't complain about the above example but it would fail with a runtime error -> type checking would be unsound.
Another idea: mypy could give a more useful error message when it detects an issue like the original one.
Consider this potential output, for example:
$ mypy file.py
file.py:7: error: Argument 1 to "f" has incompatible type Dict[str, List[int]]; expected Dict[str, Sequence[int]]
file.py:8: note: The second type parameter of "Dict" is invariant; consider using "Mapping" instead, which is covariant
This would give more context even for somebody who doesn't understand covariance/invariance -- these terms are easy to google.
Even better, we could give a pointer to relevant documentation.
The latter is different, though the reason is somewhat technical -- as the dictionary is immediately given as an argument to f, mypy infers a type Dict[str, Sequence[int]] for it. You could achieve the same effect my giving an annotation for data:
If you construct a dictionary as a function argument, the declared argument type effectively acts as an implicit type annotation. However, mypy doesn't look forward when inferring the type of data, so you have to give an annotation to override the default inferred type.
Got it. Thanks, @JukkaL! (The only type system I've really played with is Haskell's -- this one is in most ways much simpler, but I'm just starting to learn the differences.)
Activity
gvanrossum commentedon Jan 11, 2016
JukkaL commentedon Jan 11, 2016
The behavior is correct, as the second type parameter to
Dictis invariant. However, if you'd useMapping[str, Sequence[int]], this should work (but it doesn't).JukkaL commentedon Jan 11, 2016
To see why mypy complains about the code, consider this slightly different example:
If the value type parameter of
Dictwould be covariant, mypy wouldn't complain about the above example but it would fail with a runtime error -> type checking would be unsound.gvanrossum commentedon Jan 11, 2016
JukkaL commentedon Jan 11, 2016
Mypy treats
Mappingas invariant, but the value type should probably be covariant, at least. The key type could also be covariant.JukkaL commentedon Jan 11, 2016
Another idea: mypy could give a more useful error message when it detects an issue like the original one.
Consider this potential output, for example:
This would give more context even for somebody who doesn't understand covariance/invariance -- these terms are easy to google.
Even better, we could give a pointer to relevant documentation.
gvanrossum commentedon Jan 11, 2016
rmcgibbo commentedon Jan 11, 2016
I would have thought that the two snippets
and
would either both typecheck, or both fail to typecheck, but I'm kind of new at this.
Let me know if you want me to close this issue, since it seems taken care of.
JukkaL commentedon Jan 11, 2016
The latter is different, though the reason is somewhat technical -- as the dictionary is immediately given as an argument to
f, mypy infers a typeDict[str, Sequence[int]]for it. You could achieve the same effect my giving an annotation fordata:If you construct a dictionary as a function argument, the declared argument type effectively acts as an implicit type annotation. However, mypy doesn't look forward when inferring the type of
data, so you have to give an annotation to override the default inferred type.rmcgibbo commentedon Jan 11, 2016
Got it. Thanks, @JukkaL! (The only type system I've really played with is Haskell's -- this one is in most ways much simpler, but I'm just starting to learn the differences.)
gvanrossum commentedon Jan 11, 2016
Robert, can we close this issue (now that we've explained the reason and filed the issues for actual bugs)?