bpo-45198: __set_name__ documentation not clear about its usage with non-descriptor classes (GH-28439)

This commit is contained in:
Raymond Hettinger 2021-09-18 01:49:43 -05:00 committed by GitHub
parent a6e8db5e8e
commit 94b462686b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 30 deletions

View File

@ -1774,28 +1774,6 @@ class' :attr:`~object.__dict__`.
Called to delete the attribute on an instance *instance* of the owner class. Called to delete the attribute on an instance *instance* of the owner class.
.. method:: object.__set_name__(self, owner, name)
Called at the time the owning class *owner* is created. The
descriptor has been assigned to *name*.
.. note::
:meth:`__set_name__` is only called implicitly as part of the
:class:`type` constructor, so it will need to be called explicitly with
the appropriate parameters when a descriptor is added to a class after
initial creation::
class A:
pass
descr = custom_descriptor()
A.attr = descr
descr.__set_name__(A, 'attr')
See :ref:`class-object-creation` for more details.
.. versionadded:: 3.6
The attribute :attr:`__objclass__` is interpreted by the :mod:`inspect` module The attribute :attr:`__objclass__` is interpreted by the :mod:`inspect` module
as specifying the class where this object was defined (setting this as specifying the class where this object was defined (setting this
appropriately can assist in runtime introspection of dynamic class attributes). appropriately can assist in runtime introspection of dynamic class attributes).
@ -1984,6 +1962,33 @@ class defining the method.
.. versionadded:: 3.6 .. versionadded:: 3.6
When a class is created, :meth:`type.__new__` scans the class variables
and makes callbacks to those with a :meth:`__set_name__` hook.
.. method:: object.__set_name__(self, owner, name)
Automatically called at the time the owning class *owner* is
created. The object has been assigned to *name* in that class::
class A:
x = C() # Automatically calls: x.__set_name__(A, 'x')
If the class variable is assigned after the class is created,
:meth:`__set_name__` will not be called automatically.
If needed, :meth:`__set_name__` can be called directly::
class A:
pass
c = C()
A.x = c # The hook is not called
c.__set_name__(A, 'x') # Manually invoke the hook
See :ref:`class-object-creation` for more details.
.. versionadded:: 3.6
.. _metaclasses: .. _metaclasses:
Metaclasses Metaclasses
@ -2133,15 +2138,15 @@ current call is identified based on the first argument passed to the method.
Failing to do so will result in a :exc:`RuntimeError` in Python 3.8. Failing to do so will result in a :exc:`RuntimeError` in Python 3.8.
When using the default metaclass :class:`type`, or any metaclass that ultimately When using the default metaclass :class:`type`, or any metaclass that ultimately
calls ``type.__new__``, the following additional customisation steps are calls ``type.__new__``, the following additional customization steps are
invoked after creating the class object: invoked after creating the class object:
* first, ``type.__new__`` collects all of the descriptors in the class 1) The ``type.__new__`` method collects all of the attributes in the class
namespace that define a :meth:`~object.__set_name__` method; namespace that define a :meth:`~object.__set_name__` method;
* second, all of these ``__set_name__`` methods are called with the class 2) Those ``__set_name__`` methods are called with the class
being defined and the assigned name of that particular descriptor; being defined and the assigned name of that particular attribute;
* finally, the :meth:`~object.__init_subclass__` hook is called on the 3) The :meth:`~object.__init_subclass__` hook is called on the
immediate parent of the new class in its method resolution order. immediate parent of the new class in its method resolution order.
After the class object is created, it is passed to the class decorators After the class object is created, it is passed to the class decorators
included in the class definition (if any) and the resulting object is bound included in the class definition (if any) and the resulting object is bound

View File

@ -8458,7 +8458,8 @@ update_all_slots(PyTypeObject* type)
} }
/* Call __set_name__ on all descriptors in a newly generated type */ /* Call __set_name__ on all attributes (including descriptors)
in a newly generated type */
static int static int
type_new_set_names(PyTypeObject *type) type_new_set_names(PyTypeObject *type)
{ {