Reputation: 1087
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