MethodType/FunctionType and decorators

Alex Martelli aleax at mac.com
Wed Jul 4 21:41:09 EDT 2007


Alex Popescu <the.mindstorm.mailinglist at gmail.com> wrote:
   ...
> - when testing from outside the class definition, the function is
> already attached to the class instance and this is the reason why its
> type is instancemethod

To be more precise: when you access any attribute of a class (or
instance thereof), Python checks if that attribute is a descriptor (i.e.
the attribute's type has a __get__ method -- there are finer
distinctions based on whether it also has a __set__ method, i.e. is or
isn't a "data descriptor", but they don't come into play here).

A function does have in its type a __get__ method, IOW every
(Python-coded) function is a descriptor (a non-data one, btw).

So, when you access C.f where C is a class and f's type is Python-coded
function, you get the results of calling __get__ on that f object
itself.  Those results are... the envelope, please!... ta-da: a newly
minted method object (whose im_func is f).


> - for decorators, my test is executed before the class is defined and
> so at that moment the function is still a function; it will become a
> methodinstance only after the class definition is closed

The function object will never become a method object; it will remain a
function object (and you can get at it with C.__dict__['f'] for
example); but if you access that name as an attribute of C (or of an
instance of C), e.g. as C.f or getattr(C, 'f'), f.__get__ will be called
(and return a freshly minted method object whose im_func is f).

> Is this correct or am I just fabulating here?

You have roughly the right idea (as far as decorators are concerned),
just a slightly skewed vision of the rapport between function objects
and method objects, which I hoped I helped clarify.

Here are a few toy-level examples of what I've been saying, I hope they
can further help your understanding of function vs method issues:

>>> def f(): pass
... 
>>> class C(object): pass
... 
>>> a=C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'
>>> C.f = f
>>> a=C.f
>>> b=C.f
>>> a == b
True
>>> a is b
False
>>> type(a), type(b)
(<type 'instancemethod'>, <type 'instancemethod'>)
>>> a.im_func, b.im_func
(<function f at 0x66030>, <function f at 0x66030>)
>>> a.im_func is f is b.im_func
True
>>> c=f.__get__(C)
>>> type(c)
<type 'instancemethod'>
>>> c.im_func
<function f at 0x66030>
>>> c.im_func is C.__dict__['f'] is f
True


Alex



More information about the Python-list mailing list