Skip to content

pep-0557.rst: typos, .. code:: python directives #488

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

Closed
wants to merge 2 commits into from
Closed
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
124 changes: 90 additions & 34 deletions pep-0557.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ variables with type annotations as defined in PEP 526, "Syntax for
Variable Annotations". In this document, such variables are called
fields. Using these fields, the decorator adds generated method
definitions to the class to support instance initialization, a repr,
comparisons methods, and optionally other methods as described in the
comparison methods, and optionally other methods as described in the
Specification_ section. Such a class is called a Data Class, but
there's really nothing special about the class: the decorator adds
generated methods to the class and returns the same class it was
given.

As an example::
As an example:

.. code:: python

@dataclass
class InventoryItem:
Expand All @@ -50,7 +52,9 @@ As an example::
return self.unit_price * self.quantity_on_hand

The ``@dataclass`` decorator will add the equivalent of these methods
to the InventoryItem class::
to the InventoryItem class:

.. code:: python

def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0) -> None:
self.name = name
Expand Down Expand Up @@ -83,7 +87,7 @@ to the InventoryItem class::
return (self.name, self.unit_price, self.quantity_on_hand) >= (other.name, other.unit_price, other.quantity_on_hand)
return NotImplemented

Data Classes saves you from writing and maintaining these methods.
Data Classes save you from writing and maintaining these methods.

Rationale
=========
Expand Down Expand Up @@ -164,13 +168,17 @@ class that is called on: no new class is created.

The ``dataclass`` decorator is typically used with no parameters and
no parentheses. However, it also supports the following logical
signature::
signature:

.. code:: python

def dataclass(*, init=True, repr=True, eq=True, order=True, hash=None, frozen=False)

If ``dataclass`` is used just as a simple decorator with no
parameters, it acts as if it has the default values documented in this
signature. That is, these three uses of ``@dataclass`` are equivalent::
signature. That is, these three uses of ``@dataclass`` are equivalent:

.. code:: python

@dataclass
class C:
Expand Down Expand Up @@ -231,15 +239,19 @@ The parameters to ``dataclass`` are:
See the discussion below.

``field``'s may optionally specify a default value, using normal
Python syntax::
Python syntax:

.. code:: python

@dataclass
class C:
a: int # 'a' has no default value
b: int = 0 # assign a default value for 'b'

In this example, both ``a`` and ``b`` will be included in the added
``__init__`` method, which will be defined as::
``__init__`` method, which will be defined as:

.. code:: python

def __init__(self, a: int, b: int = 0):

Expand All @@ -251,7 +263,9 @@ For common and simple use cases, no other functionality is required.
There are, however, some Data Class features that require additional
per-field information. To satisfy this need for additional
information, you can replace the default field value with a call to
the provided ``field()`` function. The signature of ``field()`` is::
the provided ``field()`` function. The signature of ``field()`` is:

.. code:: python

def field(*, default=_MISSING, default_factory=_MISSING, repr=True,
hash=None, init=True, compare=True, metadata=None)
Expand Down Expand Up @@ -309,7 +323,9 @@ specified ``default`` value. If no ``default`` is provided, then the
class attribute will be deleted. The intent is that after the
``dataclass`` decorator runs, the class attributes will all contain
the default values for the fields, just as if the default value itself
were specified. For example, after::
were specified. For example, after:

.. code:: python

@dataclass
class C:
Expand Down Expand Up @@ -350,7 +366,9 @@ as ``self.__post_init__()``. If not ``__init__`` method is generated,
then ``__post_init__`` will not automatically be called.

Among other uses, this allows for initializing field values that
depend on one or more other fields. For example::
depend on one or more other fields. For example:

.. code:: python

@dataclass
class C:
Expand Down Expand Up @@ -390,7 +408,9 @@ the optional ``__post_init__`` method. 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::
value is not provided when creating the class:

.. code:: python

@dataclass
class C:
Expand Down Expand Up @@ -431,7 +451,9 @@ After all of the base class fields are added, it adds its own fields
to the ordered mapping. All of the generated methods will use this
combined, calculated ordered mapping of fields. Because the fields
are in insertion order, derived classes override base classes. An
example::
example:

.. code:: python

@dataclass
class Base:
Expand All @@ -446,7 +468,9 @@ example::
The final list of fields is, in order, ``x``, ``y``, ``z``. The final
type of ``x`` is ``int``, as specified in class ``C``.

The generated ``__init__`` method for ``C`` will look like::
The generated ``__init__`` method for ``C`` will look like:

.. code:: python

def __init__(self, x: int = 15, y: int = 0, z: int = 10):

Expand All @@ -455,7 +479,9 @@ Default factory functions

If a field specifies a ``default_factory``, it is called with zero
arguments when a default value for the field is needed. For example,
to create a new instance of a list, use::
to create a new instance of a list, use:

.. code:: python

l: list = field(default_factory=list)

Expand All @@ -469,7 +495,9 @@ Mutable default values
----------------------

Python stores default member variable values in class attributes.
Consider this example, not using Data Classes::
Consider this example, not using Data Classes:

.. code:: python

class C:
x = []
Expand All @@ -486,15 +514,19 @@ Consider this example, not using Data Classes::
Note that the two instances of class ``C`` share the same class
variable ``x``, as expected.

Using Data Classes, *if* this code was valid::
Using Data Classes, *if* this code was valid:

.. code:: python

@dataclass
class D:
x: List = []
def add(self, element):
self.x += element

it would generate code similar to::
it would generate code similar to:

.. code:: python

class D:
x = []
Expand All @@ -517,7 +549,9 @@ against many common errors. See `Automatically support mutable
default values`_ in the Rejected Ideas section for more details.

Using default factory functions is a way to create new instances of
mutable types as default values for fields::
mutable types as default values for fields:

.. code:: python

@dataclass
class D:
Expand All @@ -538,7 +572,9 @@ Module level helper functions
``instance`` to a dict (by using the factory function
``dict_factory``). Each Data Class is converted to a dict of its
fields, as name:value pairs. Data Classes, dicts, lists, and tuples
are recursed into. For example::
are recursed into. For example:

 .. code:: python

@dataclass
class Point:
Expand All @@ -563,7 +599,9 @@ Module level helper functions
field values. Data Classes, dicts, lists, and tuples are recursed
into.

Continuing from the previous example::
Continuing from the previous example:

 .. code:: python

assert astuple(p) == (10, 20)
assert astuple(c) == ([(0, 0), (10, 4)],)
Expand All @@ -580,14 +618,18 @@ Module level helper functions
strictly required, because any Python mechanism for creating a new
class with ``__annotations__`` can then apply the ``dataclass``
function to convert that class to a Data Class. This function is
provided as a convenience. For example::
provided as a convenience. For example:

.. code:: python

C = make_dataclass('C',
[('x', int),
('y', int, field(default=5))],
namespace={'add_one': lambda self: self.x + 1})

Is equivalent to::
Is equivalent to:

.. code:: python

@dataclass
class C:
Expand Down Expand Up @@ -667,15 +709,19 @@ Why not just use namedtuple?
False.

- Instances are always iterable, which can make it difficult to add
fields. If a library defines::
fields. If a library defines:

.. code:: python

Time = namedtuple('Time', ['hour', 'minute'])
def get_time():
return Time(12, 0)
  Time = namedtuple('Time', ['hour', 'minute'])
  def get_time():
      return Time(12, 0)

Then if a user uses this code as::
Then if a user uses this code as:

 .. code:: python

hour, minute = get_time()
  hour, minute = get_time()

then it would not be possible to add a ``second`` field to ``Time``
without breaking the user's code.
Expand Down Expand Up @@ -719,7 +765,9 @@ post-init function ``__post_init__`` never took any parameters.

The normal way of doing parameterized initialization (and not just
with Data Classes) is to provide an alternate classmethod constructor.
For example::
For example:

.. code:: python

@dataclass
class C:
Expand Down Expand Up @@ -770,7 +818,9 @@ A previous version of this PEP specified that ``init=False`` fields
would be copied from the source object to the newly created object
after ``__init__`` returned, but that was deemed to be inconsistent
with using ``__init__`` and ``__post_init__`` to initialize the new
object. For example, consider this case::
object. For example, consider this case:

.. code:: python

@dataclass
class Square:
Expand Down Expand Up @@ -806,7 +856,9 @@ Custom __init__ method

Sometimes the generated ``__init__`` method does not suffice. For
example, suppose you wanted to have an object to store ``*args`` and
``**kwargs``::
``**kwargs``:

.. code:: python

@dataclass(init=False)
class ArgHolder:
Expand All @@ -822,7 +874,9 @@ example, suppose you wanted to have an object to store ``*args`` and
A complicated example
---------------------

This code exists in a closed source project::
This code exists in a closed source project:

.. code:: python

class Application:
def __init__(self, name, requirements, constraints=None, path='', executable_links=None, executables_dir=()):
Expand All @@ -837,7 +891,9 @@ This code exists in a closed source project::
def __repr__(self):
return f'Application({self.name!r},{self.requirements!r},{self.constraints!r},{self.path!r},{self.executable_links!r},{self.executables_dir!r},{self.additional_items!r})'

This can be replaced by::
This can be replaced by:

.. code:: python

@dataclass
class Application:
Expand Down