[Python-checkins] [3.6] bpo-23702: Update Descriptor-HOWTO to reflect the removal of unbound methods (GH-3739) (#3742)

Raymond Hettinger webhook-mailer at python.org
Mon Sep 25 04:11:24 EDT 2017


https://github.com/python/cpython/commit/73c915a5cd1cdd8775cf47b77fef7ca8fd42ad96
commit: 73c915a5cd1cdd8775cf47b77fef7ca8fd42ad96
branch: 3.6
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: Raymond Hettinger <rhettinger at users.noreply.github.com>
date: 2017-09-25T01:11:21-07:00
summary:

[3.6] bpo-23702: Update Descriptor-HOWTO to reflect the removal of unbound methods (GH-3739) (#3742)

(cherry picked from commit 0d4497b9cae7942b7f731a6f99a73985c3fb4630)

files:
M Doc/howto/descriptor.rst

diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst
index b34937585ea..5e85a9aa659 100644
--- a/Doc/howto/descriptor.rst
+++ b/Doc/howto/descriptor.rst
@@ -180,7 +180,7 @@ descriptor is useful for monitoring just a few chosen attributes::
 
 The protocol is simple and offers exciting possibilities.  Several use cases are
 so common that they have been packaged into individual function calls.
-Properties, bound and unbound methods, static methods, and class methods are all
+Properties, bound methods, static methods, and class methods are all
 based on the descriptor protocol.
 
 
@@ -266,22 +266,23 @@ Python's object oriented features are built upon a function based environment.
 Using non-data descriptors, the two are merged seamlessly.
 
 Class dictionaries store methods as functions.  In a class definition, methods
-are written using :keyword:`def` and :keyword:`lambda`, the usual tools for
-creating functions.  The only difference from regular functions is that the
+are written using :keyword:`def` or :keyword:`lambda`, the usual tools for
+creating functions.  Methods only differ from regular functions in that the
 first argument is reserved for the object instance.  By Python convention, the
 instance reference is called *self* but may be called *this* or any other
 variable name.
 
 To support method calls, functions include the :meth:`__get__` method for
 binding methods during attribute access.  This means that all functions are
-non-data descriptors which return bound or unbound methods depending whether
-they are invoked from an object or a class.  In pure python, it works like
-this::
+non-data descriptors which return bound methods when they are invoked from an
+object.  In pure python, it works like this::
 
     class Function(object):
         . . .
         def __get__(self, obj, objtype=None):
             "Simulate func_descr_get() in Objects/funcobject.c"
+            if obj is None:
+                return self
             return types.MethodType(self, obj)
 
 Running the interpreter shows how the function descriptor works in practice::
@@ -291,25 +292,34 @@ Running the interpreter shows how the function descriptor works in practice::
     ...         return x
     ...
     >>> d = D()
-    >>> D.__dict__['f']  # Stored internally as a function
-    <function f at 0x00C45070>
-    >>> D.f              # Get from a class becomes an unbound method
-    <unbound method D.f>
-    >>> d.f              # Get from an instance becomes a bound method
+
+    # Access through the class dictionary does not invoke __get__.
+    # It just returns the underlying function object.
+    >>> D.__dict__['f']
+    <function D.f at 0x00C45070>
+
+    # Dotted access from a class calls __get__() which just returns
+    # the underlying function unchanged.
+    >>> D.f
+    <function D.f at 0x00C45070>
+
+    # The function has a __qualname__ attribute to support introspection
+    >>> D.f.__qualname__
+    'D.f'
+
+    # Dotted access from an instance calls __get__() which returns the
+    # function wrapped in a bound method object
+    >>> d.f
     <bound method D.f of <__main__.D object at 0x00B18C90>>
 
-The output suggests that bound and unbound methods are two different types.
-While they could have been implemented that way, the actual C implementation of
-:c:type:`PyMethod_Type` in :source:`Objects/classobject.c` is a single object
-with two different representations depending on whether the :attr:`im_self`
-field is set or is *NULL* (the C equivalent of ``None``).
-
-Likewise, the effects of calling a method object depend on the :attr:`im_self`
-field. If set (meaning bound), the original function (stored in the
-:attr:`im_func` field) is called as expected with the first argument set to the
-instance.  If unbound, all of the arguments are passed unchanged to the original
-function. The actual C implementation of :func:`instancemethod_call()` is only
-slightly more complex in that it includes some type checking.
+    # Internally, the bound method stores the underlying function,
+    # the bound instance, and the class of the bound instance.
+    >>> d.f.__func__
+    <function D.f at 0x1012e5ae8>
+    >>> d.f.__self__
+    <__main__.D object at 0x1012e1f98>
+    >>> d.f.__class__
+    <class 'method'>
 
 
 Static Methods and Class Methods



More information about the Python-checkins mailing list