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

miss-islington webhook-mailer at python.org
Sat Sep 18 03:10:08 EDT 2021


https://github.com/python/cpython/commit/7ab114bf1fa0f28ee267a4c69e597cc49a186a14
commit: 7ab114bf1fa0f28ee267a4c69e597cc49a186a14
branch: 3.10
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2021-09-18T00:10:00-07:00
summary:

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

(cherry picked from commit 94b462686b7dfabbd69cc9401037d736d71c4dc2)

Co-authored-by: Raymond Hettinger <rhettinger at users.noreply.github.com>

files:
M Doc/reference/datamodel.rst
M Objects/typeobject.c

diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index d3cf9836e3356..3713f04585750 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1739,28 +1739,6 @@ class' :attr:`~object.__dict__`.
    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
 as specifying the class where this object was defined (setting this
 appropriately can assist in runtime introspection of dynamic class attributes).
@@ -1949,6 +1927,33 @@ class defining the method.
    .. 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
@@ -2098,15 +2103,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.
 
 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:
 
-* first, ``type.__new__`` collects all of the descriptors in the class
-  namespace that define a :meth:`~object.__set_name__` method;
-* second, all of these ``__set_name__`` methods are called with the class
-  being defined and the assigned name of that particular descriptor;
-* finally, the :meth:`~object.__init_subclass__` hook is called on the
-  immediate parent of the new class in its method resolution order.
+1) The ``type.__new__`` method collects all of the attributes in the class
+   namespace that define a :meth:`~object.__set_name__` method;
+2) Those ``__set_name__`` methods are called with the class
+   being defined and the assigned name of that particular attribute;
+3) The :meth:`~object.__init_subclass__` hook is called on the
+   immediate parent of the new class in its method resolution order.
 
 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
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index d966d36b4d42b..dc06cf0a0c11b 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8428,7 +8428,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
 type_new_set_names(PyTypeObject *type)
 {



More information about the Python-checkins mailing list