gh-103810: Fix broken references in dataclasses (#103811)

Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
This commit is contained in:
Olga Matoula 2023-04-24 17:26:18 -06:00 committed by GitHub
parent 8291ae31dd
commit 0f23eda4b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 73 deletions

View file

@ -12,8 +12,8 @@
-------------- --------------
This module provides a decorator and functions for automatically This module provides a decorator and functions for automatically
adding generated :term:`special method`\s such as :meth:`__init__` and adding generated :term:`special method`\s such as :meth:`~object.__init__` and
:meth:`__repr__` to user-defined classes. It was originally described :meth:`~object.__repr__` to user-defined classes. It was originally described
in :pep:`557`. in :pep:`557`.
The member variables to use in these generated methods are defined The member variables to use in these generated methods are defined
@ -31,7 +31,7 @@ using :pep:`526` type annotations. For example, this code::
def total_cost(self) -> float: def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand return self.unit_price * self.quantity_on_hand
will add, among other things, a :meth:`__init__` that looks like:: will add, among other things, a :meth:`~object.__init__` that looks like::
def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0): def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
self.name = name self.name = name
@ -86,86 +86,86 @@ Module contents
The parameters to :func:`dataclass` are: The parameters to :func:`dataclass` are:
- ``init``: If true (the default), a :meth:`__init__` method will be - ``init``: If true (the default), a :meth:`~object.__init__` method will be
generated. generated.
If the class already defines :meth:`__init__`, this parameter is If the class already defines :meth:`~object.__init__`, this parameter is
ignored. ignored.
- ``repr``: If true (the default), a :meth:`__repr__` method will be - ``repr``: If true (the default), a :meth:`~object.__repr__` method will be
generated. The generated repr string will have the class name and generated. The generated repr string will have the class name and
the name and repr of each field, in the order they are defined in the name and repr of each field, in the order they are defined in
the class. Fields that are marked as being excluded from the repr the class. Fields that are marked as being excluded from the repr
are not included. For example: are not included. For example:
``InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)``. ``InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)``.
If the class already defines :meth:`__repr__`, this parameter is If the class already defines :meth:`~object.__repr__`, this parameter is
ignored. ignored.
- ``eq``: If true (the default), an :meth:`__eq__` method will be - ``eq``: If true (the default), an :meth:`~object.__eq__` method will be
generated. This method compares the class as if it were a tuple generated. This method compares the class as if it were a tuple
of its fields, in order. Both instances in the comparison must of its fields, in order. Both instances in the comparison must
be of the identical type. be of the identical type.
If the class already defines :meth:`__eq__`, this parameter is If the class already defines :meth:`~object.__eq__`, this parameter is
ignored. ignored.
- ``order``: If true (the default is ``False``), :meth:`__lt__`, - ``order``: If true (the default is ``False``), :meth:`~object.__lt__`,
:meth:`__le__`, :meth:`__gt__`, and :meth:`__ge__` methods will be :meth:`~object.__le__`, :meth:`~object.__gt__`, and :meth:`~object.__ge__` methods will be
generated. These compare the class as if it were a tuple of its generated. These compare the class as if it were a tuple of its
fields, in order. Both instances in the comparison must be of the fields, in order. Both instances in the comparison must be of the
identical type. If ``order`` is true and ``eq`` is false, a identical type. If ``order`` is true and ``eq`` is false, a
:exc:`ValueError` is raised. :exc:`ValueError` is raised.
If the class already defines any of :meth:`__lt__`, If the class already defines any of :meth:`~object.__lt__`,
:meth:`__le__`, :meth:`__gt__`, or :meth:`__ge__`, then :meth:`~object.__le__`, :meth:`~object.__gt__`, or :meth:`~object.__ge__`, then
:exc:`TypeError` is raised. :exc:`TypeError` is raised.
- ``unsafe_hash``: If ``False`` (the default), a :meth:`__hash__` method - ``unsafe_hash``: If ``False`` (the default), a :meth:`~object.__hash__` method
is generated according to how ``eq`` and ``frozen`` are set. is generated according to how ``eq`` and ``frozen`` are set.
:meth:`__hash__` is used by built-in :meth:`hash()`, and when objects are :meth:`~object.__hash__` is used by built-in :meth:`hash()`, and when objects are
added to hashed collections such as dictionaries and sets. Having a added to hashed collections such as dictionaries and sets. Having a
:meth:`__hash__` implies that instances of the class are immutable. :meth:`~object.__hash__` implies that instances of the class are immutable.
Mutability is a complicated property that depends on the programmer's Mutability is a complicated property that depends on the programmer's
intent, the existence and behavior of :meth:`__eq__`, and the values of intent, the existence and behavior of :meth:`~object.__eq__`, and the values of
the ``eq`` and ``frozen`` flags in the :func:`dataclass` decorator. the ``eq`` and ``frozen`` flags in the :func:`dataclass` decorator.
By default, :func:`dataclass` will not implicitly add a :meth:`__hash__` By default, :func:`dataclass` will not implicitly add a :meth:`~object.__hash__`
method unless it is safe to do so. Neither will it add or change an method unless it is safe to do so. Neither will it add or change an
existing explicitly defined :meth:`__hash__` method. Setting the class existing explicitly defined :meth:`~object.__hash__` method. Setting the class
attribute ``__hash__ = None`` has a specific meaning to Python, as attribute ``__hash__ = None`` has a specific meaning to Python, as
described in the :meth:`__hash__` documentation. described in the :meth:`~object.__hash__` documentation.
If :meth:`__hash__` is not explicitly defined, or if it is set to ``None``, If :meth:`~object.__hash__` is not explicitly defined, or if it is set to ``None``,
then :func:`dataclass` *may* add an implicit :meth:`__hash__` method. then :func:`dataclass` *may* add an implicit :meth:`~object.__hash__` method.
Although not recommended, you can force :func:`dataclass` to create a Although not recommended, you can force :func:`dataclass` to create a
:meth:`__hash__` method with ``unsafe_hash=True``. This might be the case :meth:`~object.__hash__` method with ``unsafe_hash=True``. This might be the case
if your class is logically immutable but can nonetheless be mutated. if your class is logically immutable but can nonetheless be mutated.
This is a specialized use case and should be considered carefully. This is a specialized use case and should be considered carefully.
Here are the rules governing implicit creation of a :meth:`__hash__` Here are the rules governing implicit creation of a :meth:`~object.__hash__`
method. Note that you cannot both have an explicit :meth:`__hash__` method. Note that you cannot both have an explicit :meth:`~object.__hash__`
method in your dataclass and set ``unsafe_hash=True``; this will result method in your dataclass and set ``unsafe_hash=True``; this will result
in a :exc:`TypeError`. in a :exc:`TypeError`.
If ``eq`` and ``frozen`` are both true, by default :func:`dataclass` will If ``eq`` and ``frozen`` are both true, by default :func:`dataclass` will
generate a :meth:`__hash__` method for you. If ``eq`` is true and generate a :meth:`~object.__hash__` method for you. If ``eq`` is true and
``frozen`` is false, :meth:`__hash__` will be set to ``None``, marking it ``frozen`` is false, :meth:`~object.__hash__` will be set to ``None``, marking it
unhashable (which it is, since it is mutable). If ``eq`` is false, unhashable (which it is, since it is mutable). If ``eq`` is false,
:meth:`__hash__` will be left untouched meaning the :meth:`__hash__` :meth:`~object.__hash__` will be left untouched meaning the :meth:`~object.__hash__`
method of the superclass will be used (if the superclass is method of the superclass will be used (if the superclass is
:class:`object`, this means it will fall back to id-based hashing). :class:`object`, this means it will fall back to id-based hashing).
- ``frozen``: If true (the default is ``False``), assigning to fields will - ``frozen``: If true (the default is ``False``), assigning to fields will
generate an exception. This emulates read-only frozen instances. If generate an exception. This emulates read-only frozen instances. If
:meth:`__setattr__` or :meth:`__delattr__` is defined in the class, then :meth:`~object.__setattr__` or :meth:`~object.__delattr__` is defined in the class, then
:exc:`TypeError` is raised. See the discussion below. :exc:`TypeError` is raised. See the discussion below.
- ``match_args``: If true (the default is ``True``), the - ``match_args``: If true (the default is ``True``), the
``__match_args__`` tuple will be created from the list of ``__match_args__`` tuple will be created from the list of
parameters to the generated :meth:`__init__` method (even if parameters to the generated :meth:`~object.__init__` method (even if
:meth:`__init__` is not generated, see above). If false, or if :meth:`~object.__init__` is not generated, see above). If false, or if
``__match_args__`` is already defined in the class, then ``__match_args__`` is already defined in the class, then
``__match_args__`` will not be generated. ``__match_args__`` will not be generated.
@ -173,18 +173,18 @@ Module contents
- ``kw_only``: If true (the default value is ``False``), then all - ``kw_only``: If true (the default value is ``False``), then all
fields will be marked as keyword-only. If a field is marked as fields will be marked as keyword-only. If a field is marked as
keyword-only, then the only effect is that the :meth:`__init__` keyword-only, then the only effect is that the :meth:`~object.__init__`
parameter generated from a keyword-only field must be specified parameter generated from a keyword-only field must be specified
with a keyword when :meth:`__init__` is called. There is no with a keyword when :meth:`~object.__init__` is called. There is no
effect on any other aspect of dataclasses. See the effect on any other aspect of dataclasses. See the
:term:`parameter` glossary entry for details. Also see the :term:`parameter` glossary entry for details. Also see the
:const:`KW_ONLY` section. :const:`KW_ONLY` section.
.. versionadded:: 3.10 .. versionadded:: 3.10
- ``slots``: If true (the default is ``False``), :attr:`__slots__` attribute - ``slots``: If true (the default is ``False``), :attr:`~object.__slots__` attribute
will be generated and new class will be returned instead of the original one. will be generated and new class will be returned instead of the original one.
If :attr:`__slots__` is already defined in the class, then :exc:`TypeError` If :attr:`~object.__slots__` is already defined in the class, then :exc:`TypeError`
is raised. is raised.
.. versionadded:: 3.10 .. versionadded:: 3.10
@ -215,7 +215,7 @@ Module contents
b: int = 0 # assign a default value for 'b' b: int = 0 # assign a default value for 'b'
In this example, both ``a`` and ``b`` will be included in the added In this example, both ``a`` and ``b`` will be included in the added
:meth:`__init__` method, which will be defined as:: :meth:`~object.__init__` method, which will be defined as::
def __init__(self, a: int, b: int = 0): def __init__(self, a: int, b: int = 0):
@ -256,13 +256,13 @@ Module contents
error to specify both ``default`` and ``default_factory``. error to specify both ``default`` and ``default_factory``.
- ``init``: If true (the default), this field is included as a - ``init``: If true (the default), this field is included as a
parameter to the generated :meth:`__init__` method. parameter to the generated :meth:`~object.__init__` method.
- ``repr``: If true (the default), this field is included in the - ``repr``: If true (the default), this field is included in the
string returned by the generated :meth:`__repr__` method. string returned by the generated :meth:`~object.__repr__` method.
- ``hash``: This can be a bool or ``None``. If true, this field is - ``hash``: This can be a bool or ``None``. If true, this field is
included in the generated :meth:`__hash__` method. If ``None`` (the included in the generated :meth:`~object.__hash__` method. If ``None`` (the
default), use the value of ``compare``: this would normally be default), use the value of ``compare``: this would normally be
the expected behavior. A field should be considered in the hash the expected behavior. A field should be considered in the hash
if it's used for comparisons. Setting this value to anything if it's used for comparisons. Setting this value to anything
@ -275,8 +275,8 @@ Module contents
is excluded from the hash, it will still be used for comparisons. is excluded from the hash, it will still be used for comparisons.
- ``compare``: If true (the default), this field is included in the - ``compare``: If true (the default), this field is included in the
generated equality and comparison methods (:meth:`__eq__`, generated equality and comparison methods (:meth:`~object.__eq__`,
:meth:`__gt__`, et al.). :meth:`~object.__gt__`, et al.).
- ``metadata``: This can be a mapping or None. None is treated as - ``metadata``: This can be a mapping or None. None is treated as
an empty dict. This value is wrapped in an empty dict. This value is wrapped in
@ -287,7 +287,7 @@ Module contents
namespace in the metadata. namespace in the metadata.
- ``kw_only``: If true, this field will be marked as keyword-only. - ``kw_only``: If true, this field will be marked as keyword-only.
This is used when the generated :meth:`__init__` method's This is used when the generated :meth:`~object.__init__` method's
parameters are computed. parameters are computed.
.. versionadded:: 3.10 .. versionadded:: 3.10
@ -435,13 +435,13 @@ Module contents
Class, raises :exc:`TypeError`. If values in ``changes`` do not Class, raises :exc:`TypeError`. If values in ``changes`` do not
specify fields, raises :exc:`TypeError`. specify fields, raises :exc:`TypeError`.
The newly returned object is created by calling the :meth:`__init__` The newly returned object is created by calling the :meth:`~object.__init__`
method of the dataclass. This ensures that method of the dataclass. This ensures that
:meth:`__post_init__`, if present, is also called. :ref:`__post_init__ <post-init-processing>`, if present, is also called.
Init-only variables without default values, if any exist, must be 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 specified on the call to :func:`replace` so that they can be passed to
:meth:`__init__` and :meth:`__post_init__`. :meth:`~object.__init__` and :ref:`__post_init__ <post-init-processing>`.
It is an error for ``changes`` to contain any fields that are It is an error for ``changes`` to contain any fields that are
defined as having ``init=False``. A :exc:`ValueError` will be raised defined as having ``init=False``. A :exc:`ValueError` will be raised
@ -449,7 +449,7 @@ Module contents
Be forewarned about how ``init=False`` fields work during a call to Be forewarned about how ``init=False`` fields work during a call to
:func:`replace`. They are not copied from the source object, but :func:`replace`. They are not copied from the source object, but
rather are initialized in :meth:`__post_init__`, if they're rather are initialized in :ref:`__post_init__ <post-init-processing>`, if they're
initialized at all. It is expected that ``init=False`` fields will initialized at all. It is expected that ``init=False`` fields will
be rarely and judiciously used. If they are used, it might be wise be rarely and judiciously used. If they are used, it might be wise
to have alternate class constructors, or perhaps a custom to have alternate class constructors, or perhaps a custom
@ -480,7 +480,7 @@ Module contents
:const:`KW_ONLY` is otherwise completely ignored. This includes the :const:`KW_ONLY` is otherwise completely ignored. This includes the
name of such a field. By convention, a name of ``_`` is used for a name of such a field. By convention, a name of ``_`` is used for a
:const:`KW_ONLY` field. Keyword-only fields signify :const:`KW_ONLY` field. Keyword-only fields signify
:meth:`__init__` parameters that must be specified as keywords when :meth:`~object.__init__` parameters that must be specified as keywords when
the class is instantiated. the class is instantiated.
In this example, the fields ``y`` and ``z`` will be marked as keyword-only fields:: In this example, the fields ``y`` and ``z`` will be marked as keyword-only fields::
@ -501,20 +501,22 @@ Module contents
.. exception:: FrozenInstanceError .. exception:: FrozenInstanceError
Raised when an implicitly defined :meth:`__setattr__` or Raised when an implicitly defined :meth:`~object.__setattr__` or
:meth:`__delattr__` is called on a dataclass which was defined with :meth:`~object.__delattr__` is called on a dataclass which was defined with
``frozen=True``. It is a subclass of :exc:`AttributeError`. ``frozen=True``. It is a subclass of :exc:`AttributeError`.
.. _post-init-processing:
Post-init processing Post-init processing
-------------------- --------------------
The generated :meth:`__init__` code will call a method named The generated :meth:`~object.__init__` code will call a method named
:meth:`__post_init__`, if :meth:`__post_init__` is defined on the :meth:`!__post_init__`, if :meth:`!__post_init__` is defined on the
class. It will normally be called as ``self.__post_init__()``. class. It will normally be called as ``self.__post_init__()``.
However, if any ``InitVar`` fields are defined, they will also be However, if any ``InitVar`` fields are defined, they will also be
passed to :meth:`__post_init__` in the order they were defined in the passed to :meth:`!__post_init__` in the order they were defined in the
class. If no :meth:`__init__` method is generated, then class. If no :meth:`~object.__init__` method is generated, then
:meth:`__post_init__` will not automatically be called. :meth:`!__post_init__` will not automatically be called.
Among other uses, this allows for initializing field values that 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::
@ -528,10 +530,10 @@ depend on one or more other fields. For example::
def __post_init__(self): def __post_init__(self):
self.c = self.a + self.b self.c = self.a + self.b
The :meth:`__init__` method generated by :func:`dataclass` does not call base The :meth:`~object.__init__` method generated by :func:`dataclass` does not call base
class :meth:`__init__` methods. If the base class has an :meth:`__init__` method 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 that has to be called, it is common to call this method in a
:meth:`__post_init__` method:: :meth:`!__post_init__` method::
@dataclass @dataclass
class Rectangle: class Rectangle:
@ -545,12 +547,12 @@ that has to be called, it is common to call this method in a
def __post_init__(self): def __post_init__(self):
super().__init__(self.side, self.side) super().__init__(self.side, self.side)
Note, however, that in general the dataclass-generated :meth:`__init__` methods Note, however, that in general the dataclass-generated :meth:`~object.__init__` methods
don't need to be called, since the derived dataclass will take care of 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. initializing all fields of any base class that is a dataclass itself.
See the section below on init-only variables for ways to pass 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. :func:`replace` handles ``init=False`` fields.
Class variables Class variables
@ -573,8 +575,8 @@ 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 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 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 module-level :func:`fields` function. Init-only fields are added as
parameters to the generated :meth:`__init__` method, and are passed to parameters to the generated :meth:`~object.__init__` method, and are passed to
the optional :meth:`__post_init__` method. They are not otherwise used the optional :ref:`__post_init__ <post-init-processing>` method. They are not otherwise used
by dataclasses. by dataclasses.
For example, suppose a field will be initialized from a database, if a For example, suppose a field will be initialized from a database, if a
@ -601,12 +603,12 @@ Frozen instances
It is not possible to create truly immutable Python objects. However, It is not possible to create truly immutable Python objects. However,
by passing ``frozen=True`` to the :meth:`dataclass` decorator you can by passing ``frozen=True`` to the :meth:`dataclass` decorator you can
emulate immutability. In that case, dataclasses will add emulate immutability. In that case, dataclasses will add
:meth:`__setattr__` and :meth:`__delattr__` methods to the class. These :meth:`~object.__setattr__` and :meth:`~object.__delattr__` methods to the class. These
methods will raise a :exc:`FrozenInstanceError` when invoked. methods will raise a :exc:`FrozenInstanceError` when invoked.
There is a tiny performance penalty when using ``frozen=True``: There is a tiny performance penalty when using ``frozen=True``:
:meth:`__init__` cannot use simple assignment to initialize fields, and :meth:`~object.__init__` cannot use simple assignment to initialize fields, and
must use :meth:`object.__setattr__`. must use :meth:`~object.__setattr__`.
Inheritance Inheritance
----------- -----------
@ -634,14 +636,14 @@ example::
The final list of fields is, in order, ``x``, ``y``, ``z``. The final The final list of fields is, in order, ``x``, ``y``, ``z``. The final
type of ``x`` is ``int``, as specified in class ``C``. type of ``x`` is ``int``, as specified in class ``C``.
The generated :meth:`__init__` method for ``C`` will look like:: The generated :meth:`~object.__init__` method for ``C`` will look like::
def __init__(self, x: int = 15, y: int = 0, z: int = 10): def __init__(self, x: int = 15, y: int = 0, z: int = 10):
Re-ordering of keyword-only parameters in :meth:`__init__` Re-ordering of keyword-only parameters in :meth:`~object.__init__`
---------------------------------------------------------- ------------------------------------------------------------------
After the parameters needed for :meth:`__init__` are computed, any After the parameters needed for :meth:`~object.__init__` are computed, any
keyword-only parameters are moved to come after all regular keyword-only parameters are moved to come after all regular
(non-keyword-only) parameters. This is a requirement of how (non-keyword-only) parameters. This is a requirement of how
keyword-only parameters are implemented in Python: they must come keyword-only parameters are implemented in Python: they must come
@ -662,7 +664,7 @@ fields, and ``Base.x`` and ``D.z`` are regular fields::
z: int = 10 z: int = 10
t: int = field(kw_only=True, default=0) t: int = field(kw_only=True, default=0)
The generated :meth:`__init__` method for ``D`` will look like:: The generated :meth:`~object.__init__` method for ``D`` will look like::
def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: int = 0): def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: int = 0):
@ -671,7 +673,7 @@ the list of fields: parameters derived from regular fields are
followed by parameters derived from keyword-only fields. followed by parameters derived from keyword-only fields.
The relative ordering of keyword-only parameters is maintained in the The relative ordering of keyword-only parameters is maintained in the
re-ordered :meth:`__init__` parameter list. re-ordered :meth:`~object.__init__` parameter list.
Default factory functions Default factory functions
@ -683,10 +685,10 @@ example, to create a new instance of a list, use::
mylist: list = field(default_factory=list) mylist: list = field(default_factory=list)
If a field is excluded from :meth:`__init__` (using ``init=False``) If a field is excluded from :meth:`~object.__init__` (using ``init=False``)
and the field also specifies ``default_factory``, then the default and the field also specifies ``default_factory``, then the default
factory function will always be called from the generated factory function will always be called from the generated
:meth:`__init__` function. This happens because there is no other :meth:`~object.__init__` function. This happens because there is no other
way to give the field an initial value. way to give the field an initial value.
Mutable default values Mutable default values

View file

@ -111,7 +111,6 @@ Doc/library/csv.rst
Doc/library/ctypes.rst Doc/library/ctypes.rst
Doc/library/curses.ascii.rst Doc/library/curses.ascii.rst
Doc/library/curses.rst Doc/library/curses.rst
Doc/library/dataclasses.rst
Doc/library/datetime.rst Doc/library/datetime.rst
Doc/library/dbm.rst Doc/library/dbm.rst
Doc/library/decimal.rst Doc/library/decimal.rst