从数据类中的自定义构造函数调用生成的 __init__ 作为默认值
是否可以从 dataclasses.field
中受益,特别是对于默认值,但使用自定义构造函数?我知道 @dataclass
注释在生成的 __init__
中设置默认值,如果我替换它,就不会再这样做了。那么,是否可以替换生成的__init__
,并仍然在内部调用它?
@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
self.i = 2*a
解决方法是定义 __new__
而不是覆盖 __init__
,但我更愿意避免这种情况。
这个问题非常接近,但是答案仅涉及作为代码示例给出的特定用例。另外,我不想使用
__post_init__
因为我需要使用__setattr__
这是静态类型检查的问题,并且它无助于调整< code>__init__ 无论如何都会采取。我不想使用类方法,我真的希望调用者使用自定义构造函数。
这个也很接近,但这只是解释为什么新的构造函数替换了生成的构造函数,而不是如何仍然调用后者(还有一个回复建议使用 Pydantic,但是我不想子类化
BaseModel
,因为它会扰乱我的继承)。
因此,简而言之,我希望受益于 dataclass 的功能,即拥有属性的默认值,而不需要繁琐的解决方法。请注意,原始默认值对我来说不是一个选项,因为它设置类属性:
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
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
self.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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
据我所知,更干净的方法是有一个替代类方法用作构造函数:这样,数据类将完全按照预期工作,您可以这样做:
但是如果您不想要显式构造函数方法,并且确实需要调用
A()
,它可以通过创建一个装饰器来完成,该装饰器将在@dataclass
之后应用 - 然后它可以移动__init__ 为另一个名称。唯一的事情是您的自定义
__init__
必须调用另一个名称,否则@dataclass
将不会创建该方法。As I perceive it, the cleaner approach there is to have an alternative classmethod to use as your constructor: this way, the dataclass would work exactly as intended and you could just do:
But if you don't want an explicit constructor method, and really need to call just
A()
, it can be done by creating a decorator, that will be applied after@dataclass
- it can then move__init__
to another name. The only thng being that your custom__init__
has to be called another name, otherwise@dataclass
won't create the method.