Search code examples
python-3.xpyright

How to avoid type checker warnings due to default values set in __init__?


In my app there are many cases of classes that essentially behave like this:

class A:

    def __init__(self) -> None:
        self.subject = None

    def set_subject(self, subject: SpecificClass) -> None:
        self.subject = subject

    def do_something_with_subject(self) -> None:
        self.subject.do_stuff()

It's an invariant of the program that do_something_with_subject() is always called after set_subject(), but I must create class A before I know what to set the subject to, so right now I'm setting default values in __init__(). In the case of subject, the only logical default value is None.

Now for the problem: my static type checker (pyright) complains about self.subject.do_stuff(). Since it sees in __init__() that subject can be None, it tells me that do_stuff() is not a member of None. All very reasonable, except that this is not a warning I wish to see, given how my program operates. I also:

  • Like the idea of declaring all instance variables in __init__(). It gives you an overview of the class contents, and I also hear that some IDEs look into __init__() for autocompletion information.
  • Don't want to use type-checker-specific directives in the code to silence this warning, because I want other developers to be free to use their own preferred type checker.
  • Don't want to annotate subject with something like Any that excludes it from the type checking.

Is there some way I can have my cake and eat it too in this case? Keep subject under type checking scrutiny, keep it somehow declared in __init__(), and not have the type checker think it can be None?


Solution

  • This can be achieved by using cast. self.subject = cast(SpecificClass, None) will return the value (None) unchanged, but will signal to the type checker that it has a specific type (SpecificClass).