[Python-bugs-list] [ python-Bugs-535444 ] super() broken with classmethods

noreply@sourceforge.net noreply@sourceforge.net
Sun, 31 Mar 2002 12:19:01 -0800


Bugs item #535444, was opened at 2002-03-26 22:13
You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=535444&group_id=5470

Category: Python Interpreter Core
Group: Python 2.2.1 candidate
Status: Open
Resolution: None
Priority: 5
Submitted By: Phillip J. Eby (pje)
Assigned to: Nobody/Anonymous (nobody)
Summary: super() broken with classmethods

Initial Comment:
Using super() in a classmethod breaks in Python 2.2. 
Apparently, when super looks up an attribute from the
__mro__ sequence, it calls the found descriptor's
__get__ with the descriptor itself as the 'type'
argument, which breaks horribly with class methods
(which always binds to the type argument).

Presumably, the fix is to pass a NULL type argument,
which should work with the recent fixes to the
classmethod's __get__ logic.  In other words, this code
in the super_getattro function Objects/typeobject.c:

tmp = f(res, su->obj, res);

should probably actually read:

tmp = f(res, su->obj, NULL);



----------------------------------------------------------------------

>Comment By: Michael Hudson (mwh)
Date: 2002-03-31 20:19

Message:
Logged In: YES 
user_id=6656

Unless someone can come up with a obviously correct patch 
(and convince Guido that it's obviously correct) very soon, 
this isn't going to go into 2.2.1.


----------------------------------------------------------------------

Comment By: Phillip J. Eby (pje)
Date: 2002-03-27 13:38

Message:
Logged In: YES 
user_id=56214

Ugh.  I just realized that my "presumable fix" is actually
wrong.  I checked back on my "Python super" workaround, and
realized I modified Guido's example slightly, to call
__get__(self.__obj__,starttype), instead of
__get__(self.__obj__).  This implies that the fix to
super_getattro is a little more complicated, since
super_getattro doesn't have a C variable equivalent to
starttype in the Python version of super.  :(


----------------------------------------------------------------------

Comment By: Phillip J. Eby (pje)
Date: 2002-03-27 13:06

Message:
Logged In: YES 
user_id=56214

class cm1(object):
    def cmm(klass):
        print klass
    cmm = classmethod(cmm)

class cm2(cm1):
    def cmm(klass):
        super(cm2,klass).cmm()
    cmm = classmethod(cmm)

cm2.cmm()

The above code prints "<classmethod object at 0x00A9B930>",
demonstrating that super(cm2,klass).cmm is bound improperly.
 (It should print <class '__main__.cm2'>, analagous to how
calling cm1.cmm() directly prints <class '__main__.cm1'>.) 
You can more specifically verify this like so:

>>> cm1.cmm.im_self
<class '__main__.cm1'>
>>> cm2.cmm.im_self
<class '__main__.cm2'>
>>> super(cm2,cm2).cmm.im_self
<classmethod object at 0x00A9B930>
>>> 

The last item's im_self should of course be <class
'__main__.cm2'>.  As I said, the problem is that
super_getattro incorrectly asks the classmethod descriptor
to bind to *itself*, rather than to a type.

Note that if you use the pure Python example version of
"super" defined in the python.org/2.2/descrintro.html
document, the above examples work correctly as long as you
use a version of Python that has the "classmethod core dump"
problem fixed.  However, the builtin super() never works
correctly for classmethods, whether the "classmethod core
dump" is fixed or not.


----------------------------------------------------------------------

Comment By: Martin v. Löwis (loewis)
Date: 2002-03-27 12:26

Message:
Logged In: YES 
user_id=21627

Can you give an example of how to break it? Please also
report what your example does when you run it.

----------------------------------------------------------------------

You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=535444&group_id=5470