Requirement:
I have a class with many fields initialized in __init__
method. Some of these fields should be possible to reset to initial values via a reset()
method.
I would like to provide typing info for these attributes and make Flake, MyPy, PyCharm (and me) happy with the solution.
Possible solutions:
Duplicate initial values
In this solution all tools (MyPy, Flake, PyCharm) are happy but not me. I have initial values in two places (
__init__
andreset
) and I need to keep them in sync. There is a possibility that if in the future one initial value needs to be modified, then I will not change it in both places.class Test: def __init__(self) -> None: self.persistentCounter: int = 0 self.resetableCounter: int = 1 # the same value is in reset method. Keep them in sync!!! # seven more attributes of different types and initial values def reset(self) -> None: self.resetableCounter = 1 # the same value is in __init__ method. Keep them in sync!!! # reset remaining seven attributes to the same values as in __init__()
Keep initial values in one method only
The fix seems to be easy: keep initial values in
reset
method only and callreset
from__init__
.class Test: def __init__(self) -> None: self.persistentCounter: int = 0 self.reset() def reset(self) -> None: self.resetableCounter: int = 1 # seven more attributes of different types and initial values
I'm happy (and Flake8 and MyPy too) with such solution but PyCharm complains that
Instance attribute resetableCounter defined outside __init__
This warning can be switched off, but sometimes it is useful - when I forgot to define some attribute in neither
__init__
norreset
method.Define attributes as
None
So we can improve the second solution - define attribute inside
__init__
but set it asNone
and then call thereset
method.from typing import Optional class Test: def __init__(self) -> None: self.persistentCounter: int = 0 self.resetableCounter: Optional[int] = None # seven more attributes of different types - all defined as Optional self.reset() def reset(self) -> None: self.resetableCounter = 1 # seven more attributes with different initial values def foo(self) -> bool: return self.resetableCounter > 10
The downside of this solution is that the attribute is defined as
Optional[int]
, notint
and when I use it for example in thefoo
method, then mypy complainserror: Unsupported operand types for < ("int" and "None") note: Left operand is of type "Optional[int]"
This can be fixed when I put an additional assert inside
foo
method:def foo(self) -> bool: assert self.resetableCounter is not None return self.resetableCounter > 10
It makes all tools happy but not me - I do not want to fill the source code with many "unnecessary" assertions.
Question:
How to fulfill the requirement specified above and mitigate downsides of presented solutions?
Instance attribute attribute_name defined outside __init__ describes a similar issue but no answer fits my requirement (see above).