Skip to content

Commit

Permalink
pythongh-101100: Improve documentation for attributes on instance met…
Browse files Browse the repository at this point in the history
…hods (python#112832)
  • Loading branch information
AlexWaygood authored Dec 8, 2023
1 parent e4c0876 commit ed21d0c
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 41 deletions.
2 changes: 1 addition & 1 deletion Doc/library/inspect.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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__ <instance-methods>` attribute (etc) when an object passes
:attr:`~method.__func__` attribute (etc) when an object passes
:func:`ismethod`.


Expand Down
23 changes: 14 additions & 9 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <builtin-methods>` (such as :meth:`append`
on lists) and :ref:`class instance method <instance-methods>`.
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 <instance-methods>`) 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__ <method.__self__>` is the object on which the method
operates, and :attr:`m.__func__ <method.__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 <user-defined-funcs>`, 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):
Expand All @@ -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
Expand Down
77 changes: 52 additions & 25 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -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 <method-binding>`

* - .. 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 <str>` 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-funcs>`.

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 <user-defined-funcs>` 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 <user-defined-funcs>` 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 <user-defined-funcs>`
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
Expand Down Expand Up @@ -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
^^^^^^^^^^^^^^^^

Expand All @@ -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 <method.__self__>`.)


Classes
Expand Down Expand Up @@ -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__`.
Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions Doc/tutorial/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <instance-methods>` have attributes, too:
:attr:`m.__self__ <method.__self__>` is the instance
object with the method :meth:`!m`, and :attr:`m.__func__ <method.__func__>` is
the :ref:`function object <user-defined-funcs>`
corresponding to the method.


Expand Down
4 changes: 2 additions & 2 deletions Doc/whatsnew/2.6.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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__ <instance-methods>`, and :attr:`!im_func` is also available as
:ref:`__func__ <instance-methods>`.
: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
Expand Down
5 changes: 3 additions & 2 deletions Doc/whatsnew/2.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <classmethod>` and
:class:`@staticmethod <staticmethod>` to wrap
methods as class or static methods, the wrapper object now
exposes the wrapped function as their :ref:`__func__ <instance-methods>`
exposes the wrapped function as their :attr:`~method.__func__`
attribute.
(Contributed by Amaury Forgeot d'Arc, after a suggestion by
George Sakkis; :issue:`5982`.)
Expand Down

0 comments on commit ed21d0c

Please sign in to comment.