Search code examples
pythonpython-typingpython-dataclasses

How to handle typing of member variable that is initialized during __post_init__() of dataclass


The variable below is initialized as none, but during __post_init__ it is replaced with an instance of outlook client.

@dataclass
class Config:
    """Outlook configuration"""

    mailbox: str
    inbox: str
    mailbox_obj: Union["Mailbox", None] = None

However, static type analysis correctly informs that mailbox_obj has no members (...is not a known member of "None"). I don't want to guard everything with if mailbox_obj just to satisfy the type analysis. Is there another way using a dataclass field or something?

The problem would go away if I just used a regular class since I can initialize the problem variable in init where the type will be inferred to it's set value, but then I have to write that extra boilerplate.

Writing this question has reminded me of the below, which is probably what I'm looking for:

    mailbox_obj: "Mailbox" = field(init=False)

Is that the right way?


Solution

  • Yes, you want to specify that it is not an init field, so you just want something like this:

    import dataclasses
    
    class Mailbox:
        pass
    
    @dataclasses.dataclass
    class Config:
        """Outlook configuration"""
    
        mailbox: str
        inbox: str
        mailbox_obj: "Mailbox" = dataclasses.field(init=False)
    
        def __post_init__(self):
            # do some stuff...
            self.mailbox_obj = Mailbox()
    

    I saved the above code in a file called test_typing.py and here is mypy:

    (py310) Juans-MBP:test juan$ mypy test_typing.py
    Success: no issues found in 1 source file