Repository navigation
Closed
Description
Description
When using msgspec.structs.replace to create a new object, the __post_init__ method is not called (unlike with dataclass.replace).
from dataclasses import dataclass, replace
import msgspec
@dataclass
class D:
x: int
def __post_init__(self):
print("dataclass: post init called")
class M(msgspec.Struct):
x: int
def __post_init__(self):
print("msgspec: post init called")
d = D(1)
m = M(1)
d2 = replace(d, x=2)
m2 = msgspec.structs.replace(m, x=2)
# Output:
# dataclass: post init called
# msgspec: post init called
# dataclass: post init calledTested with python 3.13.5.
Metadata
Metadata
Assignees
Labels
No labels
Activity
provinzkraut commentedon Oct 26, 2025
Looking at the PR that introduced this, it seems like
__post_init__is intentionally not called when doingcopyorreplaceoperations. I am not entirely sure why that is, but it should probably at least be mentioned in the documentation, as this behaviour differs from e.g. dataclasses.kramar11 commentedon Nov 3, 2025
Thanks for looking into this.
But I think msgspec should really be calling
__post_init__to behave like dataclasses. Also when usingcopy.replacecurrently__post_init__is not called unlike dataclasses does. This is a very unexpected behaviour for devs using msgspec as a dataclass replacement and only mentioning this in the documentation is in my opinion not really the right thing to do.provinzkraut commentedon Nov 15, 2025
Yeah, I guess it makes sense to keep the behaviour the same. I've created #933 with a fix and some open questions.
Siyet commentedon Apr 8, 2026
Ported to the community fork msgspec-arise: issue #25, PR #32