Python extension modules
Mark Hammond
MarkH at ActiveState.com
Thu Nov 1 06:31:17 EST 2001
[posted and mailed]
emdpek wrote:
> I need Python objects to contain and "represent" native C
> structs. Is there a way to do this *without* defining a new
> type?
Check out the struct module. It allows you to pack and unpack "blobs"
of data (usually in a string), given a format string.
So one approach would be to define a Python class in a .py file, that
wraps up the struct module.
import struct
class Foo:
def __init__(self, int1=0, int2=0):
self.int1=int1
self.int2=int2
def __getattr__(self, attr):
if attr=="_value_":
return struct.pack("ii", self.int1, self.int2)
raise AttributeError, "%r.%s" % (self, attr)
f=Foo(int2=1)
f.int1=255
print "Data is", repr(f._value_)
--
Yields: Data is '\xff\x00\x00\x00\x01\x00\x00\x00'
Your extension module could create instances of this class to return to
callers. Something like:
(error checking omitted, but _do_ add it :)
{
...
CSTRUCT cs;
PyObject *mod = PyImport_ImportModule("foo");
PyObject *cls = PyObject_GetAttrString(mod, "Foo");
PyObject *args = Py_BuildValue(cs.int1, cs.int2);
PyObject *instance = PyEval_CallObject(cls, args);
Py_DECREF(args);
Py_DECREF(cls);
// instance is a new object ready to return, with a new reference
}
It could accept class instances as params - use something like:
{
...
PyObject *inst, *str;
CSTRUCT cs;
PyArg_ParseTuple("O", &inst);
str=PyObject_GetAttrString(inst, "_value_");
if (!PyString_Check(str)) ...
if (PyString_Length(str)!= sizeof(cs)) // eek...
memcpy(&cs, PyString_AsString(str), sizeof(cs));
Py_DECREF(str);
...
}
The other alternative, as you discovered, is what you outline below:
> Question about defining a new type, then. Functions
> (package-scoped functions not tied to a class) are declared
> via the PyMethodDef array, right? So, this is where an
> instance constructor might go?
[snip lots of stuff that looked correct, but I really didn't look too hard]
> static PyObject*
> MyNew_getattr(MyNew *self, char *name)
You should use Python declarations exactly - use "PyObject" instead of
"MyNew". MyNew may fail in some C++ scenarios.
> {
> return Py_FindMethod(MyNew_methods, (PyObject *)self, name);
> }
>
>
> So, now you can: "rv = instance.method()"
Yep. You can also add simple checks to getattr to make it look more
like a struct:
static PyObject*
MyNew_getattr(PyObject *self, char *name)
{
if (strcmp(name, "int1")==0)
return PyInt_FromLong( ((MyNew *)self)->pcs->int1);
else if ...
// try methods last.
return Py_FindMethod(MyNew_methods, (PyObject *)self, name);
}
> Is this (use of "getattr" method, which calls Py_FindMethod)
> the accepted convention?
>
> Am I on the right track? Thanks in advance...
Yep :)
> P.S. There is perhaps a train-of-thought missing from the
> Extending tutorial that I lost hair figuring out this
> morning. I would be more than happy to offer possible
> improvements, if there is interest...
Sure is! If submit patches to the documentation to the source-forge
patch manager, you would be loved by many :)
Mark.
More information about the Python-list
mailing list