Reputation: 650
I'm writing a Python C extension that wraps an external C library. In the original library there are structs (of type T
for the sake of the discussion), so my extension class looks like this:
typedef struct {
PyObject_HEAD
T *cdata;
} TWrapperBase;
I also need to look up pointers in Python from time to time, so I exposed a read-only field _cdata
that is a cdata
pointer as unsigned long long
(yes, I know it's not very portable, but it's out of scope now).
Then, I want to be able to add some more methods in Python, but I can't just append them to a class declared in C, so I subclass it and add my new methods:
class TWrapper(TWrapperBase):
...
Now, in my C extension code I need a way of accesing cdata
field, so I can pass it to library functions. I know that self
won't be an instance of TWrapperBase
, but rather TWrapper
(this Python version). What is the proper way to do this?
static PyObject * doStuff(PyObject *self)
{
T *cdata_ptr;
// How to get a pointer to cdata?
//
// This looks very unsafe to me, do I have any guarantee of
// the subclass memory layout?
// 1. cdata_ptr = ((TWrapperBase*)self)->cdata
//
// This is probably safe, but it seems to be a bit of a hassle
// to query it with a string key
// 2. cdata_ptr = PyLong_AsVoidPtr(PyObject_GetAttrString(self, "_cdata"))
do_important_library_stuff(cdata_ptr);
Py_INCREF(self);
return self;
}
Thanks!
Upvotes: 3
Views: 669
Reputation: 281152
// This looks very unsafe to me, do I have any guarantee of
// the subclass memory layout?
// 1. cdata_ptr = ((TWrapperBase*)self)->cdata
Yeah, that works. You can look at all the implementations of Python's built-in types and see that they do pretty much the same thing, usually without checking whether they're operating on a subclass instance.
Upvotes: 3