summaryrefslogtreecommitdiffstats
path: root/Doc/howto/descriptor.rst
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2017-09-25 08:05:49 (GMT)
committerGitHub <noreply@github.com>2017-09-25 08:05:49 (GMT)
commit0d4497b9cae7942b7f731a6f99a73985c3fb4630 (patch)
treeb5f851a1faa88bac357428046c0bf9b3f0bd02a0 /Doc/howto/descriptor.rst
parent0bf287b6e0a42877b06cbea5d0fe6474d8061caa (diff)
downloadcpython-0d4497b9cae7942b7f731a6f99a73985c3fb4630.zip
cpython-0d4497b9cae7942b7f731a6f99a73985c3fb4630.tar.gz
cpython-0d4497b9cae7942b7f731a6f99a73985c3fb4630.tar.bz2
bpo-23702: Update Descriptor-HOWTO to reflect the removal of unbound methods (#3739)
Diffstat (limited to 'Doc/howto/descriptor.rst')
-rw-r--r--Doc/howto/descriptor.rst56
1 files changed, 33 insertions, 23 deletions
diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst
index b349375..5e85a9a 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