How to instantiate a custom Python class inside a C extension?
MRAB
python at mrabarnett.plus.com
Wed Apr 1 15:43:09 EDT 2020
On 2020-04-01 13:42, Musbur wrote:
> 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:
>
[snip]
Try this instead:
#include <Python.h>
typedef struct {
PyObject_HEAD
void* data;
} SeriesObject;
static PyTypeObject SeriesType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "_Series",
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_doc = "SeriesObject (msec, value) object",
};
PyObject* make_series(PyObject* unused) {
SeriesObject* series;
series = PyObject_New(SeriesObject, &SeriesType);
series->data = NULL;
fprintf(stderr, "New SeriesObject at %p\n", series);
return (PyObject*)series;
}
static void Series_dealloc(PyObject* self_) {
SeriesObject* self;
self = (SeriesObject*)self_;
fprintf(stderr, "Deallocate SeriesObject at %p\n", self);
PyObject_DEL(self);
}
PyObject* Series_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
SeriesObject* self;
self = (SeriesObject*)type->tp_alloc(type, 0);
self->data = NULL;
fprintf(stderr, "New Series at %p\n", self);
return (PyObject*)self;
}
static PyMethodDef Series_methods[] = {
{NULL, NULL, 0, NULL}
};
static PyMethodDef module_methods[] = {
{"make_series", (PyCFunction)make_series, METH_NOARGS,
"Instantiate and return a new SeriesObject object."},
{NULL, NULL, 0, NULL}
};
static PyModuleDef series_module = {
PyModuleDef_HEAD_INIT,
"series",
"Defines the SeriesObject (time, value) class"
,
-1,
module_methods
};
PyMODINIT_FUNC PyInit_series(void) {
PyObject* m;
m = PyModule_Create(&series_module);
SeriesType.tp_dealloc = Series_dealloc;
SeriesType.tp_new = Series_new;
SeriesType.tp_methods = Series_methods;
if (PyType_Ready(&SeriesType) < 0)
return NULL;
PyModule_AddObject(m, "Series", (PyObject*)&SeriesType);
return m;
}
More information about the Python-list
mailing list