This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: dataclasses.replace breaks when __init__ is overrriden in subclass
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.10, Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: SebastianSpeitel, eric.smith
Priority: normal Keywords:

Created on 2021-04-28 09:34 by SebastianSpeitel, last changed 2022-04-11 14:59 by admin.

Messages (4)
msg392174 - (view) Author: Sebastian Speitel (SebastianSpeitel) Date: 2021-04-28 09:34
from dataclasses import dataclass, replace

@dataclass()
class A:
    a: int

class B(A):
    def __init__(self):
        super().__init__(a=1)

obj1 = B()
obj2 = replace(obj1, a=2)

  File "/usr/lib/python3.9/dataclasses.py", line 1284, in replace
    return obj.__class__(**changes)
TypeError: __init__() got an unexpected keyword argument 'a'


When a class extends a dataclass and overrides `__init__`, `replace` still accepts it as a dataclass according to the PEP but fails at constructing, since the `__init__`-signature doesn't match anymore.
msg392175 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-04-28 09:43
I'm open to suggestions on how this could be fixed, but I don't see how it's possible. I guess the best thing to do would be to fail if __init__() isn't the one that was generated by @dataclass. But that might be too pessimistic: the user could have provided a __init__() that does work with replace(), and such a change would start breaking that code.
msg392176 - (view) Author: Sebastian Speitel (SebastianSpeitel) Date: 2021-04-28 09:56
One solution I thought of was to return not an object of the same instance, but one of the same dataclass, which would allow the implementation to traverse the class hierachy of the object and create an instance of the first dataclass-class (or class with same __init__ signature) it finds with the changes applied.

This would at least allow using replace instead of it just failing in more cases.

But according to the PEP
> Creates a new object of the same type of [the] instance
the returned object has to have the same type.
msg392180 - (view) Author: Sebastian Speitel (SebastianSpeitel) Date: 2021-04-28 10:17
Or maybe a cls argument which defaults to obj.__class__?
History
Date User Action Args
2022-04-11 14:59:44adminsetgithub: 88131
2021-04-28 10:17:45SebastianSpeitelsetmessages: + msg392180
2021-04-28 09:56:14SebastianSpeitelsetmessages: + msg392176
2021-04-28 09:43:54eric.smithsetversions: + Python 3.10, - Python 3.7, Python 3.8
nosy: + eric.smith

messages: + msg392175

assignee: eric.smith
2021-04-28 09:34:28SebastianSpeitelcreate