Search code examples
pythoninstance-variablespython-dataclasses

Mixing instance attributes and fields in Python data classes


I would like to "mix and match" instance attributes and dataclass fields, effectively extending dataclasses to optional attributes with computable values. I try to do this by using a default dataclass (so no explicit init method), but instantiating instance attributes (not Fields) in __post_init__. That does not seem to please my IDE, though, as it warns me that these attributes were "defined outside an init method".

import dataclasses from typing import Optional, List

@dataclasses.dataclass
class Word:
    text: str

    def __post_init__(self):
        self.chars: List[str] = self.text.split()
        self.alt_text: Optional[str] = None
        self.alt_text_chars: Optional[List[str]] = None

    def add_alt_text(self, text: str):
        self.alt_text = text  # IDE complains that instance attribute is defined outside init
        self.alt_text_chars = text.split()  # IDE complains


word = Word("hello")
word.add_alt_text("good morning")

Does that mean that what I want to achieve is not possible, i.e. mixing instance attributes alongside regular dataclass fields? Or is there a (PEP-y) way around that is allowed?

As a side note: sometimes you explicitly want attributes to not be treated the same as fields. For instance, when your dataclass has __eq__ (the default), then you may want to compare ONLY the fields but not all of its attributes.


Solution

  • You can manage fields by listing them in the dataclass using field() and passing init=False and compare=False to the field call, although I am not sure this is what you are looking for.