diff options
author | Erik De Bonte <erikd@microsoft.com> | 2022-07-05 18:09:41 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-05 18:09:41 (GMT) |
commit | 5f319308a820f49fec66fc3ade50bbaa9fe2105d (patch) | |
tree | 6600ec4edc8b24484f25062bb7c237c7754ae88b /Doc | |
parent | 36fcde61ba48c4e918830691ecf4092e4e3b9b99 (diff) | |
download | cpython-5f319308a820f49fec66fc3ade50bbaa9fe2105d.zip cpython-5f319308a820f49fec66fc3ade50bbaa9fe2105d.tar.gz cpython-5f319308a820f49fec66fc3ade50bbaa9fe2105d.tar.bz2 |
gh-91330: Tests and docs for dataclass descriptor-typed fields (GH-94424)
Co-authored-by: Ćukasz Langa <lukasz@langa.pl>
Diffstat (limited to 'Doc')
-rw-r--r-- | Doc/library/dataclasses.rst | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index ec50696..4364ac3 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -749,3 +749,54 @@ mutable types as default values for fields:: ``dict``, or ``set``, unhashable objects are now not allowed as default values. Unhashability is used to approximate mutability. + +Descriptor-typed fields +----------------------- + +Fields that are assigned :ref:`descriptor objects <descriptors>` as their +default value have the following special behaviors: + +* The value for the field passed to the dataclass's ``__init__`` method is + passed to the descriptor's ``__set__`` method rather than overwriting the + descriptor object. +* Similarly, when getting or setting the field, the descriptor's + ``__get__`` or ``__set__`` method is called rather than returning or + overwriting the descriptor object. +* To determine whether a field contains a default value, ``dataclasses`` + will call the descriptor's ``__get__`` method using its class access + form (i.e. ``descriptor.__get__(obj=None, type=cls)``. If the + descriptor returns a value in this case, it will be used as the + field's default. On the other hand, if the descriptor raises + :exc:`AttributeError` in this situation, no default value will be + provided for the field. + +:: + + class IntConversionDescriptor: + def __init__(self, *, default): + self._default = default + + def __set_name__(self, owner, name): + self._name = "_" + name + + def __get__(self, obj, type): + if obj is None: + return self._default + + return getattr(obj, self._name, self._default) + + def __set__(self, obj, value): + setattr(obj, self._name, int(value)) + + @dataclass + class InventoryItem: + quantity_on_hand: IntConversionDescriptor = IntConversionDescriptor(default=100) + + i = InventoryItem() + print(i.quantity_on_hand) # 100 + i.quantity_on_hand = 2.5 # calls __set__ with 2.5 + print(i.quantity_on_hand) # 2 + +Note that if a field is annotated with a descriptor type, but is not assigned +a descriptor object as its default value, the field will act like a normal +field. |