static, class and instance methods

Steve D'Aprano steve+python at pearwood.info
Fri Oct 7 04:50:56 EDT 2016


On Fri, 7 Oct 2016 04:01 pm, ast wrote:

> 
> "Gregory Ewing" <greg.ewing at canterbury.ac.nz> a écrit dans le message de
> news:e5mgi9Fp1bsU1 at mid.individual.net...
>> Lawrence D’Oliveiro wrote:
>>>
>>> Every function is already a descriptor.
>>
>> Which you can see with a simple experiment:
>>
>> >>> def f(self):
>> ...  print("self =", self)
>> ...
> 
> I thought yesterday that every thing was clear. But I have
> a doubt now with the following line:
> 
>> >>> g = f.__get__(17, None)
> 
> The signature of  __get__ method is  __get__ (self, inst, owner)  so
> once again the first parameter is filled automatically.
> Is method __get__ itself a descriptor with an attribute __get__ to perform
> the operation ? Hum, it would be endless ...

No it is not:

py> def f(): pass
...
py> hasattr(f.__get__, '__get__')
False


So what kind of thing is f.__get__? f itself is a function, which looks like
this:

py> f
<function f at 0xb7b83fa4>


but f.__get__ is something different:

py> f.__get__
<method-wrapper '__get__' of function object at 0xb7b83fa4>


"Method-wrapper" is an undocumented internal implementation detail. It isn't
part of the Python language, just part of the runtime implementation. If we
use Jython instead, we see something different:

steve at orac:~$ jython
Jython 2.5.1+ (Release_2_5_1, Aug 4 2010, 07:18:19)
[OpenJDK Server VM (Sun Microsystems Inc.)] on java1.6.0_31
Type "help", "copyright", "credits" or "license" for more information.
>>> def f(): pass
...
>>> f
<function f at 0x1>
>>> f.__get__
<built-in method __get__ of function object at 0x1>


So the Python language doesn't make any promises about what sort of thing
__get__ will be, only that it exists and is callable. Anything I say here
is an implementation detail: it may change in the future, it may have
already changed, and different Python implementations may do things
differently.

Back to CPython: f.__get__ is a method-wrapper. That gives us a hint that
although __get__ itself isn't a descriptor, it is a thing returned by
something which is a descriptor.

Remember that all functions are instances of a built-in class, FunctionType:

py> from types import FunctionType
py> assert type(f) is FunctionType
py> vars(FunctionType)['__get__']
<slot wrapper '__get__' of 'function' objects>

It is *that* "slot wrapper" thing which is itself a descriptor:

py> vars(FunctionType)['__get__'].__get__
<method-wrapper '__get__' of wrapper_descriptor object at 0xb7cf2504>

and it returns f.__get__:

py> vars(FunctionType)['__get__'].__get__(f)
<method-wrapper '__get__' of function object at 0xb7b83fa4>

which returns a method:

py> class X(object): pass
...
py> x = X()
py> vars(FunctionType)['__get__'].__get__(f)(x, X)
<bound method X.f of <__main__.X object at 0xb7b0a92c>>




-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list