Closed
Description
Code like this is one of the most common cases where we need a variable annotation (DONE):
def f() -> None:
x = [] # mypy insists on annotation (such as List[int]) here
for i in range(5):
x.append(i * 2)
Mypy could do a better job of inferring types in cases like these:
- Variable is initialized with an empty collection (or more generally, a generic type where the type argument values are indeterminate using only local statement context).
- The first reference to the variable after initialization (in the same scope) mutates the collection and allows us to infer the item types.
These cases would still require an annotation:
- Collection is read after initialization and before mutation (this happens sometimes but not too often).
- The variable is not mutated in the scope that initializes it. For example, an attribute is initialized in
__init__
and mutated in another method.
This is related to #254.
More common examples where this should work:
(1) DONE
x = {}
x['key'] = 2
(2) DONE
x = set()
x.add(2)
Additional, less common examples (not done):
(3) [postponed -- too rare and complicated]
x = {}
x.setdefault('key', []).append(1) # this is harder than most examples
(4) DONE
x = {}
x.update({'x': 1})
(5) [rejected -- too rare]
x = set()
x |= {1, 2}
(6) DONE (#8036)
if cond():
x = []
else:
x = [1]
Similar to above but with a user-defined generic type or a standard library generic type that is not list, dict or set.
Update: After some more analysis, only defaultdict
and OrderedDict
seem common enough to support.
Not sure about this:
(8) [rejected idea]
x = []
foo(x) # Should we infer type of x from the argument type? Probably not.