UPDATE: trying to check/fill values in another function
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 = 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?
I have found this to work for me:
class Foo:
def __init__(self, x: int):
self.x = x
self.y: int # Give self.y a type but no value
def fill_values(self):
self.y = x**2
def do(self) -> int:
return self.x + self.y
Essentially all you are doing is telling mypy that self.y
will be an integer when (and if) it is initialised. Trying to call self.y
before it is initialised will raise an error and you can check if it has been initialised using hasattr(self, "y")
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With