Reputation: 358
I'm having trouble getting MyPy to pass my script which contains a dataclass
Bar
with an optional argument foos
that holds a list of Foo
objects and defaults to an empty list.
Stranger still, adding a method Bar.sum_foos()
which iterates through self.foos
raises a second MyPy error. Am I misunderstanding how to set the correct types, or is something else going on?
script.py
from __future__ import annotations
from typing import Optional
from dataclasses import dataclass, field
class Foo():
pass
@dataclass
class Bar():
foos: Optional[list[Foo]] = field(default_factory = list)
def sum_foos(self) -> float:
for foo in self.foos:
pass
return 0.0
2 MyPy errors
$ mypy script.py
script.py:12: error: Incompatible types in assignment (expression has type "List[_T]", variable has type "Optional[List[Foo]]")
script.py:15: error: Item "None" of "Optional[List[Foo]]" has no attribute "__iter__" (not iterable)
Found 2 errors in 1 file (checked 1 source file)
Versions
$ python --version
Python 3.8.12
$ mypy --version
mypy 0.950 (compiled: yes)
Upvotes: 0
Views: 1210
Reputation: 7943
Well, the code in your question is almost fine as-is. Optional[X]
is equivalent to X | None
- why do you make your list optional? This field is never None, factory means that foos
attribute will be an empty list, if not passed to the constructor. Thus declaring as list[Foo]
is more correct and eliminates all errors.
from __future__ import annotations
from typing import Optional
from dataclasses import dataclass, field
class Foo():
pass
@dataclass
class Bar():
foos: list[Foo] = field(default_factory=list)
def sum_foos(self) -> float:
for foo in self.foos:
pass
return 0.0
Upvotes: 2