Skip to content

gh-101100: Add reference doc for __post_init__ #103818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 23 additions & 22 deletions Doc/library/dataclasses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -437,19 +437,19 @@ Module contents

The newly returned object is created by calling the :meth:`~object.__init__`
method of the dataclass. This ensures that
:ref:`__post_init__ <post-init-processing>`, if present, is also called.
:meth:`__post_init__`, if present, is also called.

Init-only variables without default values, if any exist, must be
specified on the call to :func:`replace` so that they can be passed to
:meth:`~object.__init__` and :ref:`__post_init__ <post-init-processing>`.
:meth:`~object.__init__` and :meth:`__post_init__`.

It is an error for ``changes`` to contain any fields that are
defined as having ``init=False``. A :exc:`ValueError` will be raised
in this case.

Be forewarned about how ``init=False`` fields work during a call to
:func:`replace`. They are not copied from the source object, but
rather are initialized in :ref:`__post_init__ <post-init-processing>`, if they're
rather are initialized in :meth:`__post_init__`, if they're
initialized at all. It is expected that ``init=False`` fields will
be rarely and judiciously used. If they are used, it might be wise
to have alternate class constructors, or perhaps a custom
Expand Down Expand Up @@ -510,30 +510,31 @@ Module contents
Post-init processing
--------------------

The generated :meth:`~object.__init__` code will call a method named
:meth:`!__post_init__`, if :meth:`!__post_init__` is defined on the
class. It will normally be called as ``self.__post_init__()``.
However, if any ``InitVar`` fields are defined, they will also be
passed to :meth:`!__post_init__` in the order they were defined in the
class. If no :meth:`~object.__init__` method is generated, then
:meth:`!__post_init__` will not automatically be called.
.. function:: __post_init__()

Among other uses, this allows for initializing field values that
depend on one or more other fields. For example::
When defined on the class, it will be called by the generated
:meth:`~object.__init__`, normally as ``self.__post_init__()``.
However, if any ``InitVar`` fields are defined, they will also be
passed to :meth:`__post_init__` in the order they were defined in the
class. If no :meth:`~object.__init__` method is generated, then
:meth:`__post_init__` will not automatically be called.

@dataclass
class C:
a: float
b: float
c: float = field(init=False)
Among other uses, this allows for initializing field values that
depend on one or more other fields. For example::

def __post_init__(self):
self.c = self.a + self.b
@dataclass
class C:
a: float
b: float
c: float = field(init=False)

def __post_init__(self):
self.c = self.a + self.b

The :meth:`~object.__init__` method generated by :func:`dataclass` does not call base
class :meth:`~object.__init__` methods. If the base class has an :meth:`~object.__init__` method
that has to be called, it is common to call this method in a
:meth:`!__post_init__` method::
:meth:`__post_init__` method::

@dataclass
class Rectangle:
Expand All @@ -552,7 +553,7 @@ don't need to be called, since the derived dataclass will take care of
initializing all fields of any base class that is a dataclass itself.

See the section below on init-only variables for ways to pass
parameters to :meth:`!__post_init__`. Also see the warning about how
parameters to :meth:`__post_init__`. Also see the warning about how
:func:`replace` handles ``init=False`` fields.

Class variables
Expand All @@ -576,7 +577,7 @@ is an ``InitVar``, it is considered a pseudo-field called an init-only
field. As it is not a true field, it is not returned by the
module-level :func:`fields` function. Init-only fields are added as
parameters to the generated :meth:`~object.__init__` method, and are passed to
the optional :ref:`__post_init__ <post-init-processing>` method. They are not otherwise used
the optional :meth:`__post_init__` method. They are not otherwise used
by dataclasses.

For example, suppose a field will be initialized from a database, if a
Expand Down