Skip to content

__post_init__ not called from replace #874

Closed

Description

@kramar11

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 called

Tested with python 3.13.5.

Activity

  1. provinzkraut commented on Oct 26, 2025

    @provinzkraut
    Member

    Looking at the PR that introduced this, it seems like __post_init__ is intentionally not called when doing copy or replace operations. 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.

  2. kramar11 commented on Nov 3, 2025

    @kramar11
    Author

    Thanks for looking into this.
    But I think msgspec should really be calling __post_init__ to behave like dataclasses. Also when using copy.replace currently __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.

  3. provinzkraut commented on Nov 15, 2025

    @provinzkraut
    Member

    Yeah, I guess it makes sense to keep the behaviour the same. I've created #933 with a fix and some open questions.

  4. Siyet commented on Apr 8, 2026

    @Siyet
    Contributor

    Ported to the community fork msgspec-arise: issue #25, PR #32

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions