Difference between static method and a function as a class at tribute?

Duncan Booth duncan at NOSPAMrcp.co.uk
Fri Sep 6 11:01:31 EDT 2002

sismex01 at hebmex.com wrote in news:mailman.1031321469.8366.python-
list at python.org:

> Any "plain" executable found as an attribute of a class
> object, upon creating an instance of that class, is bound
> to the instance as a method.  If not, then calling
> "inst.testmethod()" should display an empty tuple.

That isn't actually what happens. An unbound or bound method is created 
from the function when you actually reference it, not when you create an 
instance of the class. A good way to see this is:

>>> class C: pass

>>> def f(x): pass

>>> C.method = f
>>> inst = C()
>>> p = inst.method
>>> q = inst.method
>>> print p
<bound method C.f of <__main__.C instance at 0x009194E8>>
>>> print q
<bound method C.f of <__main__.C instance at 0x009194E8>>
>>> print id(p), id(q)
9472384 9252640

Each access of inst.method actually gets a *different* bound method.

>>> r = C.method
>>> s = C.method
>>> print id(r), id(s)
9252512 9222064

The unbound methods are also created when you access them. So again you get 
a different one each time.

> I suspect that staticmethod(func) and classmethod(func)
> wrap the function in a proxy which first extracts some
> info from the actuall call (say, the instance's class)
> and pass *whose* arguments to the real function.

As of Python 2.2, when you try to get access an object which is stored in 
the class (not in the instance), the object's __get__ method is called. In 
the case of a function, its __get__ method creates a bound or unbound 
method as appropriate. staticmethod and class method wrap the function in 
an object with a different __get__ method:
>>> f.__get__(None, C)
<unbound method C.f>
>>> f.__get__(inst, C)
<bound method C.f of <__main__.C instance at 0x009194E8>>

staticmethod's __get__ simply returns the original function:
>>> staticmethod(f).__get__(None, C)
<function f at 0x00919878>
>>> staticmethod(f).__get__(inst, C)
<function f at 0x00919878>

classmethod's __get__ creates a method bound on the type of C instead of on 
>>> classmethod(f).__get__(None, C)
<bound method class.f of <class __main__.C at 0x009151B8>>
>>> classmethod(f).__get__(inst, C)
<bound method class.f of <class __main__.C at 0x009151B8>>

Duncan Booth                                             duncan at rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?

More information about the Python-list mailing list