[Python-bugs-list] [ python-Bugs-409355 ] Meta-class inheritance problem
noreply@sourceforge.net
noreply@sourceforge.net
Thu, 22 Mar 2001 19:38:18 -0800
Bugs item #409355, was updated on 2001-03-17 02:10
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=409355&group_id=5470
Category: Python Interpreter Core
Group: Feature Request
Status: Open
Priority: 7
Submitted By: Lorien Dunn (loriend)
Assigned to: Guido van Rossum (gvanrossum)
Summary: Meta-class inheritance problem
Initial Comment:
I've run into a bug in python 2.0. The real code that
the following pseudo code represents throws a
TypeError.
class MyDerivedClass(MyPurePythonClass,MyBoostClass):
def __init__(self):
MyPurePythonClass.__init__(self)
MyBoostClass.__init__(self)
The problem occurs in MyPurePythonClass- Python says
"unbound method must be called with class instance 1st
argument". This makes sense: I'm passing a meta-class
instead of a class. David Abrahams (the main author of
boost::python) agrees that this is a Python problem,
and that it should affect Zope as well.
I think I've found the point in the python 2.0 sorce
where it occurs:
ceval.c, line 1816 (reformatted for clarity):
/* BEGIN CODE SAMPLE */
else
{
/* Unbound methods must be called with an instance of
the class (or a derived class) as first argument */
if (na > 0 && (self = stack_pointer[-n]) != NULL
&& PyInstance_Check(self)
&& PyClass_IsSubclass((PyObject
*) (((PyInstanceObject*) self)->in_class),
class))
/* Handy-dandy */ ;
else
{
PyErr_SetString(PyExc_TypeError, "unbound
method must be called with class instance 1st
argument");
x = NULL;
break;
}
}
/* END CODE SAMPLE */
----------------------------------------------------------------------
>Comment By: Lorien Dunn (loriend)
Date: 2001-03-22 19:38
Message:
Logged In: YES
user_id=175701
Guido,
printing self.__class__ results in the text "<extension
class> MyDerivedClass.MyDerivedClass at 8121560"
David,
swapping the order of the base classes makes no difference.
Thanks.
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-03-22 19:32
Message:
Logged In: YES
user_id=6380
David, I'm not sure I agree with your theory. At Jim
Fulton's request, when creating a subclass, Python actually
looks through the base classes for one that's not a regular
class, and gives that one control of the subclass creation
process. So MyDerivedClass really should be a Boost.Python
class! (Lorien can easily verify that by printing
self.__class__.)
Otherwise, if it was a regular class, the __init__ call
woudln't have failed in the first place!
Since I don't have Boost (yet), I can't look into this
further right now, and I fear it will have to remain
unresolved until after the 2.1b2 release. But I'll try to
look into it again before the final 2.1 release.
----------------------------------------------------------------------
Comment By: David Abrahams (david_abrahams)
Date: 2001-03-22 19:09
Message:
Logged In: YES
user_id=52572
Though I haven't checked out the latest from CVS, I'm at a
loss to explain the results Lorien is getting. In
particular, Boost.Python class instances have a __class__
attribute, and Boost.Python classes have a __bases__
attribute that is a tuple. Isn't that all that should be
needed for isinstance() to work properly?...
Aha, now I remember: The first base class in the list
controls which metaclass object gets control when a derived
class is created. So the declaration of MyDerivedClass
below actually creates a regular Python class with a base
that is a Boost.Python class. At that point, everything is
beyond my control. To get it to work, at least begin by
swapping the order of the base classes.
I wonder if it would make sense to always defer to the
first extension type's type (if any) for subclass creation?
It's not a general solution (i.e. what if you have multiple
extension types in the __bases__ tuple?) but at least it
would handle this case. Surely it's less likely that a
regular Python class can make any sane use of methods from
an extension class.
-Dave
----------------------------------------------------------------------
Comment By: Lorien Dunn (loriend)
Date: 2001-03-22 13:58
Message:
Logged In: YES
user_id=175701
In the following code it returns 0.
MyDerivedClass(MyPurePythonClass, MyBoostClass):
def __init__(self):
MyBoostClass.__init__(self)
isinstance(self, MyPurePythonClass)
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-03-22 12:03
Message:
Logged In: YES
user_id=6380
OK, try this. In your Python code, what does
isinstance(self, MyPurePythonClass) return?
----------------------------------------------------------------------
Comment By: Lorien Dunn (loriend)
Date: 2001-03-22 11:59
Message:
Logged In: YES
user_id=175701
I'm afraid it still doesn't work :(
the line is (from cvs code):
ok = PyObject_IsInstance(self, class)
and the problem is that ok == 0.
Thank you for patching this- I've spent hours trying to
figure out enough about the python internals to do it
myself.
Lorien
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-03-21 11:18
Message:
Logged In: YES
user_id=6380
I *think* I've fixed this now -- please test with the
current CVS.
Please let me know if I goofed up, and I'll reopen the bug
report.
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2001-03-18 14:22
Message:
Logged In: YES
user_id=6380
Zope has several workarounds, so isn't affected.
But I agree it could be fixed. The test is there because it wants to enforce a concept: 'self' should be an instance
of the class that defines the method (where a subclass instance is fine too).
But the implementation of the test is based too much on the default implementation of classes.
Could someone please submit a patch that replaces the concrete isinstance() test with an isinstance() test similar
to that in bltinmodule.c? (Maybe we need to add a new C API, PyObject_IsInstance().)
If someone could come up with a check that conve
----------------------------------------------------------------------
Comment By: David Abrahams (david_abrahams)
Date: 2001-03-18 05:30
Message:
Logged In: YES
user_id=52572
Sorry, that anonymous comment is mine. I'm still a bit
clumsy with SourceForge.
-Dve
----------------------------------------------------------------------
Comment By: Nobody/Anonymous (nobody)
Date: 2001-03-18 05:03
Message:
Logged In: NO
I was a bit surprised to learn that this check was still in
the code after issubclass and isinstance had been fixed to
work with extension classes. Suppose you checked for a
__class__ attribute on the first argument instead (or
additionally)?
----------------------------------------------------------------------
Comment By: Tim Peters (tim_one)
Date: 2001-03-17 21:29
Message:
Logged In: YES
user_id=31435
Assigned to Guido, because I bet JimF would refuse to take
blame for this <wink>.
----------------------------------------------------------------------
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=409355&group_id=5470