DEV Community

TildAlice
TildAlice

Posted on • Originally published at tildalice.io

__post_init__ vs __new__ vs __init__: When Order Matters

The Hook That Breaks Dataclasses

Here's a test: what does this print?

from dataclasses import dataclass

@dataclass
class User:
    name: str
    email: str

    def __init__(self, name, email):
        print(f"__init__ called: {name}")
        self.name = name.upper()
        self.email = email

    def __post_init__(self):
        print(f"__post_init__ called: {self.name}")
        self.name = self.name.lower()

u = User("Alice", "alice@example.com")
print(u.name)
Enter fullscreen mode Exit fullscreen mode

If you guessed alice, you're wrong. If you guessed ALICE, you're also wrong. The answer is TypeError: __init__() missing 2 required positional arguments. The dataclass decorator generates its own __init__, and your manual one gets overridden. But if you remove the manual __init__, __post_init__ runs after the generated one, giving you alice.

This is the kind of thing you learn when you've spent an afternoon debugging why your validation logic runs in the wrong order.

Close-up view of a computer screen displaying code in a software development environment.

Photo by Mathews Jumba on Pexels

Why Python Has Three Creation Hooks


Continue reading the full article on TildAlice

Top comments (0)