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
resetmethod only and callresetfrom__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 valuesI'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__norresetmethod.Define attributes as
NoneSo we can improve the second solution - define attribute inside
__init__but set it asNoneand then call theresetmethod.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 > 10The downside of this solution is that the attribute is defined as
Optional[int], notintand when I use it for example in thefoomethod, 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
foomethod:def foo(self) -> bool: assert self.resetableCounter is not None return self.resetableCounter > 10It 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).