Is it possible to benefit from dataclasses.field
, especially for default values, but using a custom constuctor? I know the @dataclass
annotation sets default values in the generated __init__
, and won't do it anymore if I replace it. So, is it possible to replace the generated __init__
, and to still call it inside?
@dataclass
class A:
l: list[int] = field(default_factory=list)
i: int = field(default=0)
def __init__(self, a: Optional[int]): # completely different args than instance attributes
self.call_dataclass_generated_init() # call generated init to set defaults
if a is not None: # custom settings of attributes
i = 2*a
A workaround would be to define __new__
instead of overriding __init__
, but I prefer to avoid that.
This question is quite close, but the answers only address the specific use-case that is given as a code example. Also, I don't want to use
__post_init__
because I need to use__setattr__
which is an issue for static type checking, and it doesn't help tuning the arguments that__init__
will take anyway.I don't want to use a class method either, I really want callers to use the custom constructor.
This one is also close, but it's only about explaining why the new constructor replaces the generated one, not about how to still call the latter (there's also a reply suggesting to use Pydantic, but I don't want to have to subclass
BaseModel
, because it will mess my inheritance).
So, in short, I want to benefit from dataclass
's feature to have default values for attributes, without cumbersome workarounds. Note that raw default values is not an option for me because it sets class attributes:
class B:
a: int = 0 # this will create B.a class attribute, and vars(B()) will be empty
l: list[int] = [] # worse, a mutable object will be shared between instances