Repository navigation
dataclass tries to generate __init__() even though the class already defines one #148941
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Apr 23, 2026 btw I would be happy to try to fix it, if needed
- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Apr 24, 2026 Yes, this happens because
_process_classonly looks at the provided arguments and not the class attributes before adding the methods to the_FuncBuilder. The checks for methods that already exist are right at the end of the process.This is true for all of the methods and not just
__init__, but_init_fndoes some early checks before adding anything to the_FuncBuilderwhich is why you're seeing this bug. Ideally I think we'd want to keep all of this logic together so all of the checks are still happening in the same place and we're not checking everything twice.Looking at this a bit more, while I think actually generating the
__init__function anyway (which is what currently also occurs), is probably unnecessary I'm not actually as certain about this check.Take your original example and then subclass
B:from dataclasses import dataclass @dataclass class A: a: int = 1 @dataclass class B(A): b: int def __init__(self, *args, **kwargs): ... @dataclass class C(B): pass
This would be an error as
__init__isn't defined inCand so it would be generated, but the logical 'breakage' occurred inB. The current behaviour requires you to 'flag' this to some extent by settinginit=FalseonB.- added a commit that references this issue
on Jul 12, 2026 - addedpendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
on Jul 13, 2026 The docs also say
If any of the added methods already exist in the class, the behavior depends on the parameter, as documented below. The decorator returns the same class that it is called on; no new class is created.
So, I also find them inconsistent there.
Has the behavior changed in a way that was not documented? I know that we refactored dataclasses to make them faster so maybe something changed without us noticing it.
The behaviour has been the same since dataclasses were added as far as I can tell, this fails on 3.8 with the same error. For comparison this also doesn't work with
attrseven withinit=Falseasattrsalways does the check (I believe it also makes the function and puts it somewhere else if__init__exists though).In my opinion the 'correct' solution from the user's side would be to mark the class or individual fields accurately with
kw_onlyor to not use dataclasses where the class isn't really structured like a dataclass.From our side I think always doing the check would be an unnecessary breaking change, the question is do we match the documented behaviour or document the actual behaviour. If so we should do it consistently for all of the special methods1.
The decorator returns the same class that it is called on; no new class is created.
I'll note that this part has been wrong since the addition of
slots=Truewhich does create a new class and tries to pretend it's the old class.Footnotes
-
and I'll have to update my lazy method fork before proceeding on that ↩
-
Bug report
Bug description:
When running this code:
I got
TypeError: non-default argument 'b' follows default argumentHowever, if I set
init=Falsefor the second dataclass, like this:There error disappeared.
I think the error comes from the process where dataclass tries to generate the default
__init__()and checks the fields. But, if I understand correctly, this should not happen when the class already defines its own__init__().Although I'm not sure whether the behavior should be defined as a bug, I do find the results inconsistant with the docs, which says
so, intuitively, adding
init=Falseshouldn't have changed the result.CPython versions tested on:
3.12, 3.13, 3.14
Operating systems tested on:
Windows
Linked PRs