From ed21d0c1f4bd17b392e24bfd83e652723dad4ddf Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 8 Dec 2023 13:18:53 +0000 Subject: [PATCH] gh-101100: Improve documentation for attributes on instance methods (#112832) --- Doc/library/inspect.rst | 2 +- Doc/library/stdtypes.rst | 23 ++++++----- Doc/reference/datamodel.rst | 77 +++++++++++++++++++++++++------------ Doc/tutorial/classes.rst | 6 ++- Doc/whatsnew/2.6.rst | 4 +- Doc/whatsnew/2.7.rst | 5 ++- 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 0138557f5fd84c..8381e508139fbd 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -492,7 +492,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Methods implemented via descriptors that also pass one of the other tests return ``False`` from the :func:`ismethoddescriptor` test, simply because the other tests promise more -- you can, e.g., count on having the - :ref:`__func__ ` attribute (etc) when an object passes + :attr:`~method.__func__` attribute (etc) when an object passes :func:`ismethod`. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 44c13bd9474ea1..1265b5b12e492d 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5328,25 +5328,30 @@ Methods .. index:: pair: object; method Methods are functions that are called using the attribute notation. There are -two flavors: built-in methods (such as :meth:`append` on lists) and class -instance methods. Built-in methods are described with the types that support -them. +two flavors: :ref:`built-in methods ` (such as :meth:`append` +on lists) and :ref:`class instance method `. +Built-in methods are described with the types that support them. If you access a method (a function defined in a class namespace) through an instance, you get a special object: a :dfn:`bound method` (also called -:dfn:`instance method`) object. When called, it will add the ``self`` argument +:ref:`instance method `) object. When called, it will add +the ``self`` argument to the argument list. Bound methods have two special read-only attributes: -``m.__self__`` is the object on which the method operates, and ``m.__func__`` is +:attr:`m.__self__ ` is the object on which the method +operates, and :attr:`m.__func__ ` is the function implementing the method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely equivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)``. -Like function objects, bound method objects support getting arbitrary +Like :ref:`function objects `, bound method objects support +getting arbitrary attributes. However, since method attributes are actually stored on the -underlying function object (``meth.__func__``), setting method attributes on +underlying function object (:attr:`method.__func__`), setting method attributes on bound methods is disallowed. Attempting to set an attribute on a method results in an :exc:`AttributeError` being raised. In order to set a method -attribute, you need to explicitly set it on the underlying function object:: +attribute, you need to explicitly set it on the underlying function object: + +.. doctest:: >>> class C: ... def method(self): @@ -5361,7 +5366,7 @@ attribute, you need to explicitly set it on the underlying function object:: >>> c.method.whoami 'my name is method' -See :ref:`types` for more information. +See :ref:`instance-methods` for more information. .. index:: object; code, code object diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 3bcc170faa087a..27d379a8b70f31 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -519,6 +519,8 @@ These are the types to which the function call operation (see section :ref:`calls`) can be applied: +.. _user-defined-funcs: + User-defined functions ^^^^^^^^^^^^^^^^^^^^^^ @@ -654,43 +656,64 @@ callable object (normally a user-defined function). single: __name__ (method attribute) single: __module__ (method attribute) -Special read-only attributes: :attr:`__self__` is the class instance object, -:attr:`__func__` is the function object; :attr:`__doc__` is the method's -documentation (same as ``__func__.__doc__``); :attr:`~definition.__name__` is the -method name (same as ``__func__.__name__``); :attr:`__module__` is the -name of the module the method was defined in, or ``None`` if unavailable. +Special read-only attributes: + +.. list-table:: + + * - .. attribute:: method.__self__ + - Refers to the class instance object to which the method is + :ref:`bound ` + + * - .. attribute:: method.__func__ + - Refers to the original function object + + * - .. attribute:: method.__doc__ + - The method's documentation (same as :attr:`!method.__func__.__doc__`). + A :class:`string ` if the original function had a docstring, else + ``None``. + + * - .. attribute:: method.__name__ + - The name of the method (same as :attr:`!method.__func__.__name__`) + + * - .. attribute:: method.__module__ + - The name of the module the method was defined in, or ``None`` if + unavailable. Methods also support accessing (but not setting) the arbitrary function -attributes on the underlying function object. +attributes on the underlying :ref:`function object `. User-defined method objects may be created when getting an attribute of a class (perhaps via an instance of that class), if that attribute is a -user-defined function object or a class method object. +user-defined :ref:`function object ` or a +:class:`classmethod` object. + +.. _method-binding: When an instance method object is created by retrieving a user-defined -function object from a class via one of its instances, its -:attr:`__self__` attribute is the instance, and the method object is said -to be bound. The new method's :attr:`__func__` attribute is the original -function object. - -When an instance method object is created by retrieving a class method -object from a class or instance, its :attr:`__self__` attribute is the -class itself, and its :attr:`__func__` attribute is the function object +:ref:`function object ` from a class via one of its +instances, its :attr:`~method.__self__` attribute is the instance, and the +method object is said to be *bound*. The new method's :attr:`~method.__func__` +attribute is the original function object. + +When an instance method object is created by retrieving a :class:`classmethod` +object from a class or instance, its :attr:`~method.__self__` attribute is the +class itself, and its :attr:`~method.__func__` attribute is the function object underlying the class method. When an instance method object is called, the underlying function -(:attr:`__func__`) is called, inserting the class instance -(:attr:`__self__`) in front of the argument list. For instance, when +(:attr:`~method.__func__`) is called, inserting the class instance +(:attr:`~method.__self__`) in front of the argument list. For instance, when :class:`!C` is a class which contains a definition for a function :meth:`!f`, and ``x`` is an instance of :class:`!C`, calling ``x.f(1)`` is equivalent to calling ``C.f(x, 1)``. -When an instance method object is derived from a class method object, the -"class instance" stored in :attr:`__self__` will actually be the class +When an instance method object is derived from a :class:`classmethod` object, the +"class instance" stored in :attr:`~method.__self__` will actually be the class itself, so that calling either ``x.f(1)`` or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is the underlying function. -Note that the transformation from function object to instance method +Note that the transformation from :ref:`function object ` +to instance method object happens each time the attribute is retrieved from the instance. In some cases, a fruitful optimization is to assign the attribute to a local variable and call that local variable. Also notice that this @@ -774,6 +797,8 @@ set to ``None`` (but see the next item); :attr:`__module__` is the name of the module the function was defined in or ``None`` if unavailable. +.. _builtin-methods: + Built-in methods ^^^^^^^^^^^^^^^^ @@ -785,8 +810,9 @@ Built-in methods This is really a different disguise of a built-in function, this time containing an object passed to the C function as an implicit extra argument. An example of a built-in method is ``alist.append()``, assuming *alist* is a list object. In -this case, the special read-only attribute :attr:`__self__` is set to the object -denoted by *alist*. +this case, the special read-only attribute :attr:`!__self__` is set to the object +denoted by *alist*. (The attribute has the same semantics as it does with +:attr:`other instance methods `.) Classes @@ -901,8 +927,9 @@ https://www.python.org/download/releases/2.3/mro/. When a class attribute reference (for class :class:`!C`, say) would yield a class method object, it is transformed into an instance method object whose -:attr:`__self__` attribute is :class:`!C`. When it would yield a static -method object, it is transformed into the object wrapped by the static method +:attr:`~method.__self__` attribute is :class:`!C`. +When it would yield a :class:`staticmethod` object, +it is transformed into the object wrapped by the static method object. See section :ref:`descriptors` for another way in which attributes retrieved from a class may differ from those actually contained in its :attr:`~object.__dict__`. @@ -970,7 +997,7 @@ in which attribute references are searched. When an attribute is not found there, and the instance's class has an attribute by that name, the search continues with the class attributes. If a class attribute is found that is a user-defined function object, it is transformed into an instance method -object whose :attr:`__self__` attribute is the instance. Static method and +object whose :attr:`~method.__self__` attribute is the instance. Static method and class method objects are also transformed; see above under "Classes". See section :ref:`descriptors` for another way in which attributes of a class retrieved via its instances may differ from the objects actually stored in diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index 7b92e1a51b6e67..3bf138ca225ee5 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -769,8 +769,10 @@ data from a string buffer instead, and pass it as an argument. or arithmetic operators, and assigning such a "pseudo-file" to sys.stdin will not cause the interpreter to read further input from it.) -Instance method objects have attributes, too: ``m.__self__`` is the instance -object with the method :meth:`!m`, and ``m.__func__`` is the function object +:ref:`Instance method objects ` have attributes, too: +:attr:`m.__self__ ` is the instance +object with the method :meth:`!m`, and :attr:`m.__func__ ` is +the :ref:`function object ` corresponding to the method. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 8bdbb0fa352ed1..e8c1709c42abac 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1678,8 +1678,8 @@ Some smaller changes made to the core Python language are: * Instance method objects have new attributes for the object and function comprising the method; the new synonym for :attr:`!im_self` is - :ref:`__self__ `, and :attr:`!im_func` is also available as - :ref:`__func__ `. + :attr:`~method.__self__`, and :attr:`!im_func` is also available as + :attr:`~method.__func__`. The old names are still supported in Python 2.6, but are gone in 3.0. * An obscure change: when you use the :func:`locals` function inside a diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 162dd74637479a..cf6d26859bb6a2 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -858,9 +858,10 @@ Some smaller changes made to the core Python language are: .. XXX bytearray doesn't seem to be documented -* When using ``@classmethod`` and ``@staticmethod`` to wrap +* When using :class:`@classmethod ` and + :class:`@staticmethod ` to wrap methods as class or static methods, the wrapper object now - exposes the wrapped function as their :ref:`__func__ ` + exposes the wrapped function as their :attr:`~method.__func__` attribute. (Contributed by Amaury Forgeot d'Arc, after a suggestion by George Sakkis; :issue:`5982`.)