diff options
author | Raymond Hettinger <rhettinger@users.noreply.github.com> | 2017-09-25 08:05:49 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-25 08:05:49 (GMT) |
commit | 0d4497b9cae7942b7f731a6f99a73985c3fb4630 (patch) | |
tree | b5f851a1faa88bac357428046c0bf9b3f0bd02a0 /Doc | |
parent | 0bf287b6e0a42877b06cbea5d0fe6474d8061caa (diff) | |
download | cpython-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')
-rw-r--r-- | Doc/howto/descriptor.rst | 56 |
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 |