Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Anomaly in creating class methods

0 views
Skip to first unread message

venk

unread,
Nov 3, 2005, 6:19:22 AM11/3/05
to
Hi,
given below is my interaction with the interpreter.... In one case, i
have created the class method using the "famous idiom"... and in the
other, i have tried to create it outside the class definition... why
isn't the latter working ? (of course, the presence of decorators is a
different issue)....
>>> class D:
... def f(cls):
... print cls
...
>>> D.f=classmethod(D.f)
>>> D.f
<bound method classobj.f of <class __main__.D at 0xb7c99f5c>>
>>> D.f()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unbound method f() must be called with D instance as first
argument (got classobj instance instead)
>>> class D:
... def f(cls):
... print cls
... f=classmethod(f)
...
>>> D.f
<bound method classobj.f of <class __main__.D at 0xb7c9947c>>
>>> D.f()
__main__.D

Bengt Richter

unread,
Nov 3, 2005, 2:01:51 PM11/3/05
to

I think you are on very thin ice using classmethod for old-style classes.
In any case, you are not providing the same argument to classmethod
in the two examples above. I'm not sure what classmethod tries to do with
an unbound method, but it's not normal usage even in newstyle classes.
It probably just saves the callable argument as an attribute of the
classmethod instance, so the problem doesn't show until the descriptor
machinery comes into play (on attribute access and calling the bound callable).


>>> def showcmarg(f): print 'cmarg=%r'%f; return classmethod(f)
...
>>> class D:
... def f(cls): print cls
...
>>> D.f=showcmarg(D.f)
cmarg=<unbound method D.f>

Note that that was an unbound method as the arg, that gets stored in the descriptor

>>> D.f
<bound method classobj.f of <class __main__.D at 0x02EE9A1C>>


>>> D.f()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unbound method f() must be called with D instance as first argument (got classobj

tance instead)

That's just the callable (D unbound method) you gave it complaining that the descriptor is
passing the intended cls D (a classobj) instead of an instance of D to the unbound method.

>>> class D:
... def f(cls): print cls
... f = showcmarg(f)
...
cmarg=<function f at 0x02EEAE2C>

Note that this time that was a _function_ arg, because it was picked up as a local
binding during the execution of the body of the class definition, where classmethod
was called. The function will have no demands except to match its signature when the
classmethod descriptor instance calls it with first arg of D.

>>> D.f
<bound method classobj.f of <class __main__.D at 0x02EE9A7C>>
>>> D.f()
__main__.D

You could extract the normal (function) classmethod arg from the outside though:

>>> class D:
... def f(cls): print cls
...
>>> D.f=showcmarg(D.f.im_func)
cmarg=<function f at 0x02EEAD84>
>>> D.f
<bound method classobj.f of <class __main__.D at 0x02EE9A4C>>
>>> D.f()
__main__.D

Suggest migrating to new style classes consistently ;-)

Regards,
Bengt Richter

Alex Martelli

unread,
Nov 4, 2005, 12:34:22 AM11/4/05
to
venk <venkatasu...@gmail.com> wrote:

> Hi,
> given below is my interaction with the interpreter.... In one case, i
> have created the class method using the "famous idiom"... and in the
> other, i have tried to create it outside the class definition... why
> isn't the latter working ? (of course, the presence of decorators is a
> different issue)....

When you access D.f, you get an unbound method; if you want the
underlying function instead, use D.f.im_func. When you access f within
the class's body, you do get the underlying function -- that's all of
the difference that's biting you...


Alex

venk

unread,
Nov 4, 2005, 12:52:47 AM11/4/05
to
Cool,
i got it now... accessing thru attribute reference always
returns a bound or unbound method... so, D.f is an unbound method
whereas i want the "function" of the unbound method... ok,.... this
example and the nice explanations definitively thought me about
function, bound method (for which the function is just an attribute
accessed by im_func) and unbound method...
Also, calling classmethod on an unbound method instead of a function
is a strict no... no...
ok... nice concept...

But, i am at loss when i come to clearly understanding the difference
between new-style classes and classic classes.... (or should i post it
as new topic?).....

Alex Martelli

unread,
Nov 4, 2005, 1:46:11 AM11/4/05
to
venk <venkatasu...@gmail.com> wrote:

> Cool,
> i got it now... accessing thru attribute reference always
> returns a bound or unbound method... so, D.f is an unbound method

Right. Specifically, accessing through a (newstyle) class or instance
always calls the __get__ method of a descriptor [[oldstyle classes and
instances are harder to pin down -- avoid them in new code!!!]]; every
function is a descriptor, so...

> whereas i want the "function" of the unbound method... ok,.... this
> example and the nice explanations definitively thought me about
> function, bound method (for which the function is just an attribute
> accessed by im_func) and unbound method...

Great!

> Also, calling classmethod on an unbound method instead of a function
> is a strict no... no...
> ok... nice concept...

Glad you like it.

> But, i am at loss when i come to clearly understanding the difference
> between new-style classes and classic classes.... (or should i post it
> as new topic?).....

"Classic" classes (old-style) exist (and are the default) only for
LEGACY purposes; they exhibit a few problematic quirks. New-style
classes are more regular, fully predictable, easy to explain and to
understand. In new code, use new-style classes only (make sure every
class includes 'object' among its ancestors -- that's the simplest way).

And, sure, feel free to open another thread if you desire more
information about the several small differences between the new-style
object model and the old-style, legacy one.


Alex

0 new messages