Skip to content

Commit

Permalink
Issue #17: Update the PEP to describe init-only variables.
Browse files Browse the repository at this point in the history
  • Loading branch information
ericvsmith committed Nov 24, 2017
1 parent 2e7ea78 commit 3a392ab
Showing 1 changed file with 45 additions and 10 deletions.
55 changes: 45 additions & 10 deletions pep-0557.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ So, why is this PEP needed?

With the addition of PEP 526, Python has a concise way to specify the
type of class members. This PEP leverages that syntax to provide a
simple, unobtrusive way to describe Data Classes. With one exception,
simple, unobtrusive way to describe Data Classes. With two exceptions,
the specified attribute type annotation is completely ignored by Data
Classes.

Expand Down Expand Up @@ -305,8 +305,8 @@ post-init processing
--------------------

The generated ``__init__`` code will call a method named
``__dataclass_post_init__``, if it is defined on the class. It will
be called as ``self.__dataclass_post_init__()``.
``__post_init__``, if it is defined on the class. It will
be called as ``self.__post_init__()``.

Among other uses, this allows for initializing field values that
depend on one or more other fields. For example::
Expand All @@ -317,18 +317,53 @@ depend on one or more other fields. For example::
b: float
c: float = field(init=False)

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

See the section below on init-only variables for ways to pass
parameters to ``__post_init__()``.

Class variables
---------------

The one place where ``dataclass`` actually inspects the type of a
field is to determine if a field is a class variable. It does this by
seeing if the type of the field is given as of type
``typing.ClassVar``. If a field is a ``ClassVar``, it is excluded
from consideration as a field and is ignored by the Data Class
mechanisms. For more discussion, see [#]_.
One place where ``dataclass`` actually inspects the type of a field is
to determine if a field is a class variable. It does this by seeing
if the type of the field is given as of type ``typing.ClassVar``. If
a field is a ``ClassVar``, it is excluded from consideration as a
field and is ignored by the Data Class mechanisms. For more
discussion, see [#]_. Such ``ClassVar`` pseudo-fields are not
returned by the module-level ``fields()`` function.

Init-only variables
-------------------

The other place where ``dataclass`` inspects a type annotation is to
determine if a field is an init-only variable. It does this by seeing
if the type of a field is of type ``dataclasses.InitVar``. If a field
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 ``fields()`` function. Init-only fields are added as
parameters to the generated ``__init__()`` method, and are passed to
the optional ``__post_init__`` function. They are not otherwise used
by Data Classes.

For example, suppose a field will be initialzed from a database, if a
value is not provided when creating the class::

@dataclass
class C:
i: int
j: int = None
database: InitVar[DatabaseType] = None

def __post_init__(self, database):
if self.j is None and database is not None:
self.j = database.lookup('j')

c = C(10, database=my_database)

In this case, ``fields()`` will return ``Field`` objects for ``i`` and
``j``, but not for ``database``.

Frozen instances
----------------
Expand Down

0 comments on commit 3a392ab

Please sign in to comment.