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;
}
--
https://mail.python.org/mailman/listinfo/python-list