Hi guys,

I'm wondering how to create an instance of an extension class I wrote. There's a minimal self-contained C module at the bottom of this post which exports two things: 1) a class Series, and 2) a function make_series() which is supposed to create a Series object on the C side and return it. The make_series function uses PyObject_New() and PyObject_Init() to create the new instance, but all it produces is some kind of zombie instance which tends to crash the application with a segfault in real life. When instantiated from Python using Series(), I get a well-behaved instance.

I've sprinkled the New, Init and Finalize functions with fprintf()s to see what happens to the object during its lifetime.

When I run this test script:

    from series import *

    print("From Python")
    s1 = Series()
    del s1

    print("\nFrom C")
    s2 = make_series()
    del s2

I get this output:

    From Python
    New Series at 0x7f89313f6660
    Init Series at 0x7f89313f6660
    Finalize Series at 0x7f89313f6660

    From C
    Finalize Series at 0x7f89313f6678

So when created from C, neither the "new" nor the "init" functions are called on the object, only "finalize". No wonder I get segfaults in the real life application.

So how is this done right? Here's the C module:

#include <Python.h>

typedef struct {
    PyObject_HEAD
    void *data;
} Series;

static PyObject *Series_new(PyTypeObject *type,
        PyObject *args, PyObject *kw) {
    Series *self;

    self = (Series *) type->tp_alloc(type, 0);
    self->data = NULL;
    fprintf(stderr, "New Series at %p\n", self);
    return (PyObject*)self;
}

static int Series_init(Series *self, PyObject *args, PyObject *kw) {
    fprintf(stderr, "Init Series at %p\n", self);
    return 0;
}

static void Series_finalize(PyObject *self) {
    fprintf(stderr, "Finalize Series at %p\n", self);
}

static PyMethodDef series_methods[] = {
    {NULL, NULL, 0, NULL}
};

static PyTypeObject series_type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "_Series",
    .tp_basicsize = sizeof(Series),
    .tp_flags = 0
        | Py_TPFLAGS_DEFAULT
        | Py_TPFLAGS_BASETYPE,
    .tp_doc = "Series (msec, value) object",
    .tp_methods = series_methods,
    .tp_new = Series_new,
    .tp_init = (initproc) Series_init,
    .tp_dealloc = Series_finalize,
};

/* To create a new Series object directly from C */
PyObject *make_series(void *data) {
    Series *pyseries;
    pyseries = PyObject_New(Series, &series_type);
    PyObject_Init((PyObject *)pyseries, &series_type);
    pyseries->data = data;
    return (PyObject *) pyseries;
}

static PyMethodDef module_methods[] = {
    {"make_series",  (PyCFunction)make_series, METH_NOARGS,
     "Instantiate and return a new Series object."},
    {NULL, NULL, 0, NULL}
};

static PyModuleDef series_module = {
    PyModuleDef_HEAD_INIT,
    "series",
    "Defines the Series (time, value) class"
    ,
    -1,
    module_methods
};

PyMODINIT_FUNC PyInit_series(void) {
    PyObject *m;

    m = PyModule_Create(&series_module);

    if (PyType_Ready(&series_type) < 0) {
        return NULL;
    }
    PyModule_AddObject(m, "Series", (PyObject*)&series_type);
    return m;
}


--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to