You're right that consistent internal state is important, but you can accomplish this with
class MyClass:
def __init__(self, config: str):
self._config = config
And if your reaction is "that just means something else needs to call Path("config.json").read_text()", you're absolutely right! It's separation of concerns; let some other method deal with the possibility that `config.json` isn't accessible. In the real world, you'd presumably want even more specific checks that specific config values were present in the JSON file, and your constructor would look more like def __init__(self, host: str, port: int):
and you'd validate that those values are present in the same place that loads the JSON.This simple change makes code so much more readable and testable.