I have occurred problems when I learn python embeded C programming.
Here's my sample: ReadBuf.c
#include "Python.h"
static PyObject* Test_IsInstance(PyObject* self, PyObject* args){
PyObject* pTest = NULL;
PyObject* pName = NULL;
PyObject* moduleDict = NULL;
PyObject* className = NULL;
PyObject* pModule = NULL;
pName = PyString_FromString("common");
pModule = PyImport_Import(pName);
if (!pModule){
printf("can not find client.py\n");
Py_RETURN_NONE;
}
moduleDict = PyModule_GetDict(pModule);
if (!moduleDict){
printf("can not get Dict\n");
Py_RETURN_NONE;
}
className = PyDict_GetItemString(moduleDict, "Test");
if (!className){
printf("can not get className\n");
Py_RETURN_NONE;
}
PyObject* subClassName = PyDict_GetItemString(moduleDict, "pyTest");
if (! subClassName){
printf("can not get subClassName\n");
}
int k = PyClass_IsSubclass(subClassName, className);
if (!k){
printf("pyTest is not subclass of Test\n");
}
int r = PyClass_Check(className);
if (!r){
printf("className is not a class\n");
} else {
printf("className is a class\n");
}
PyObject* pInsTest = PyInstance_New(className, NULL, NULL);
PyObject_CallMethod(pInsTest, "py_printT", "()");
int ok = PyArg_ParseTuple(args, "O", &pTest);
if (!ok){
printf("parse tuple error!\n");
Py_RETURN_NONE;
}
if (!pTest){
printf("can not get the instance from python\n");
Py_RETURN_NONE;
}
PyObject_CallMethod(pTest, "py_print", "()");
if (!PyObject_IsInstance(pTest, className)){
printf("Not an instance for Test\n");
Py_RETURN_NONE;
} else {
printf("an instance for Test\n");
}
Py_RETURN_NONE;
}
static PyMethodDef readbuffer[] = {
{"testIns", Test_IsInstance, METH_VARARGS, "test for instance!"},
{NULL, NULL}
};
void initReadBuf(){
PyObject* m;
m = Py_InitModule("ReadBuf", readbuffer);
}
common.py
class Test(object):
def __init__(self):
print "Test class"
def py_printT(self):
print "Test py_print"
class pyTest(Test):
def __init__(self):
Test.__init__(self)
print "pyTest class"
def py_print(self):
print "pyTest py_print"
client.py
from common import pyTest
import ReadBuf as rb
b = pyTest()
rb.testIns(b)
When I executed it on python2.7.2, the result:
Test class
pyTest class
pyTest is not subclass of Test
className is not a class
New instance error
pyTest py_print
an instance for Test
and if I executed it on python2.4.5, the result:
Test class
pyTest class
pyTest is not subclass of Test
className is not a class
New instance error
pyTest py_print
an instance for Test
Exception exceptions.SystemError: 'Objects/classobject.c:528: bad argument to internal function' in 'garbage collection' ignored
Fatal Python error: unexpected exception during garbage collection
Aborted (core dumped)
My questions:
Why exception was thrown on python2.4.5?
I defined that pyTest
is subclass of Test
, why the result is pyTest
is not subclass of Test
?
Why className
was not a class any more when I executed PyClass_Check
function?
For className
was not a class any more, why I executed PyObject_IsInstance
, the result is true?
If I modify the definition of Test class like below, the result came normal, why?
class Test: # don't inherit object any more
The problem is that PyClass_*
function should be used only with old-style classes.
When you inherit from object
the class becomes a new-style class and you should use the PyType_*
functions, listed here.
Namely:
The result of all calls to PyClass_*
functions on new-style instance is bogus. However PyObject_IsInstance
works with both old-style and new-style classes, which explains why it returns True
anyway.
Obviously changing class Test(object)
to class Test
"solves" the strange behaviour because Test
is now an old-style class on which you should use the PyClass_*
functions.
Python2.4 is quite an old version of python and probably there is some inconsistency between the APIs. You should rebuild the C-extension for each version of python you use. (Most recent versions of python do have a stable ABI, but not python2.4 I believe).