I'm trying to use mypy in my projects, but many of the instance attributes I use are only initialized after __init__
, and not inside it. However, I do want to keep the good practice of declaring all instance attributes at __init__
, so I need some complicated solutions to make this work.
An example to how I want this to behave (currently mypy is complaining):
from typing import Optional
class Foo:
def __init__(self, x: int):
self.x = x
self.y: int = None # will initialize later, but I know it will be an int
def fill_values(self):
self.y = self.x**2
def do(self) -> int:
return self.x + self.y
Currently mypy complains about the assignment of self.y
, and wants it to be Optional
or None
.
If I agree with it and change the line to self.y: Optional[int] = None
, then mypy complains on the return value of do
, because self.y
might be None
.
The only way I found around it is to add as assert before using self.y
, like: assert self.y is not None
, which mypy picks up and understands. However, starting each method with many asserts is quite hard. I have many such values, and usually one method that initializes all of them, and all other methods runs after it.
I understand that mypy is rightfully complaining (the method do
can be called before fill_values
), but even when I try to prevent it I can't get mypy to accept this. I can extend this example by adding more functionality but mypy can't infer this:
from typing import Optional
class Foo:
def __init__(self, x: int):
self.x = x
self.y: int = None # will initialize later, but I know it will be an int
def fill_values(self):
self.y = x**2
def check_values(self):
assert self.y is not None
def do(self) -> int:
if self.y is None:
self.fill_values()
self.check_values()
return self.x + self.y
Any idea of a more elegant solution that multiple assert statements and Optional
types which obscure the code?
self.y
, what would you do ifdo
was called beforefill_values
? You probably would want to pass this decision back up to where it was being called, by perhaps raising an exception? – Blueweed# type: ignore[assignment]
comment, or you can turn this behaviour off completely by passing--no-implicit-optional
, but you'll loose the none-checks in the situations like @Blueweed described. As for validation of optionals:mypy
only understands direct assertions, not when you put them in a separate method as the inference becomes too cumbersome. – Varistor