This question is a slight spin on a previous question: Accessing the underlying struct of a PyObject
Except in my version I want to know how to expose the fields of the Point struct as members of my new type.
I have looked everywhere I could think, read numerous example Python extensions and read many tutorials, docs, etc. and have not been able to find a clean way to do this.
Below is an example of what I want to do. I have some internal struct that I would like to expose via the Python extension but I don't want to have to redefine the struct in my code. It seems like the main area that is the problem is the PyMemeberDef definition...what would the offset be of x or y inside the Point struct from the context of the PointObject struct?
Any help is much appreciated, thanks.
#include <Python.h>
#include <structmember.h>
// This is actually defined elsewhere in someone else's code.
struct Point {
int x;
int y;
};
struct PointObject {
PyObject_HEAD
struct Point* my_point;
int z;
};
static PyMemberDef point_members[] = {
{"z", T_INT, offsetof(struct PointObject, z), 0, "z field"},
{"x", T_INT, offsetof(???), 0, "point x field"},
{"y", T_INT, offsetof(???), 0, "point y field"},
{NULL}
};
static PyTypeObject PointType = {
PyObject_HEAD_INIT(NULL)
.tp_name = "Point",
.tp_basicsize = sizeof(PointObject),
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "Point objects",
.tp_members = point_members,
.tp_init = (initproc)point_init,
};
...
PyMODINIT_FUNC
initMainModule(void)
{
PyObject *m = Py_InitModule(MODULE, NULL);
// Register PointType
PointType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PointType) < 0)
return;
Py_INCREF(&PointType);
PyModule_AddObject(m, "Point", (PyObject *)&PointType);
...
}
I would highly recommend reading http://docs.python.org/release/2.6/_sources/extending/newtypes.txt, specifically the section on "Providing finer control over data attributes".
After reading this, it appears it is possible to do this by defining a collection of setter/getters for the specific members in the Point struct. It does seem a bit overkill for something as simple as this, but it appears to work just fine.
Below is an example on how to do it for the 'x' field of Point, based on adding the following code to my previous example:
static PyGetSetDef point_getset[] = {
{"x", (getter)point_get_x, (setter)point_set_x, "", NULL},
{NULL}
};
static PyObject*
point_get_x(struct PointObject *self, void *closure)
{
return Py_BuildValue("i", self->my_point->x);
}
static int
point_set_x(struct PointObject *self, PyObject *value, void *closure)
{
PyErr_SetString(PyExc_TypeError, "Attribute is read-only!");
return -1;
}
Lastly, add the point_getset struct to the tp_getset field in the previously defined PyTypeObject struct. It should be noted that you can still define members in the traditional PyMemberDef struct for the simple cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With