Nick Skywalker
Nick Skywalker

Reputation: 1087

A parent class that allows dataclass style annotations that works with nested class hierarchy

I would like to write a class that works similarly to dataclass, but would work with inheritance. It would also data to a dictionary rather than directly to the class.

Currently I have something that work only with one subclass:

class Data:
    metadata: dict

    def __init_subclass__(cls):
        hints = get_type_hints(cls)
        defaults = {k: v for k, v in cls.__dict__.items() if not k.startswith("__")}

        def __init__(self, metadata=FrozenDict(), **kwargs):
            metadata = dict(metadata)
            # Collect attributes from kwargs or defaults
            for key, typ in hints.items():
                if key == "metadata":
                    continue
                if key in kwargs:
                    metadata[key] = kwargs[key]
                elif key in defaults:
                    metadata[key] = defaults[key]
                else:
                    raise TypeError(f"Missing required argument: '{key}'")


            self.metadata = metadata

        cls.__init__ = __init__  # Override constructor dynamically

        def __repr__(self):
            if not hasattr(self, "__cached_repr"):
                self.__cached_repr = f"{cls.__name__}(metadata={repr(self.metadata)})"

            return self.__cached_repr

        cls.__repr__ = __repr__

        def __str__(self):
            if not hasattr(self, "__cached_str"):
                argstr = ",".join(
                    f"{k}={repr(v)}" for k, v in self.metadata.items() if k in hints
                )
                self.__cached_str = f"{cls.__name__}({argstr})"

            return self.__cached_str

        cls.__str__ = __str__

Example usage:

class MyData(Data):
    x: int
    y: float = 3.14  # Default value
    label: str = "default"

class NestedData(MyData):
    extra: str = "nested"

# ✅ Works for direct subclass
n1 = MyData(x=10)
# ❌ Does not work for nested subclass
n2 = NestedData(x=10)

Upvotes: 0

Views: 28

Answers (0)

Related Questions