Question

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:

  1. Why exception was thrown on python2.4.5?

  2. I defined that pyTest is subclass of Test, why the result is pyTest is not subclass of Test?

  3. Why className was not a class any more when I executed PyClass_Check function?

  4. For className was not a class any more, why I executed PyObject_IsInstance, the result is true?

  5. If I modify the definition of Test class like below, the result came normal, why?

    class Test:   # don't inherit object any more
    
Was it helpful?

Solution

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top