Skip to content

Instantly share code, notes, and snippets.

@saghul
Created August 2, 2011 21:25
Show Gist options
  • Save saghul/1121260 to your computer and use it in GitHub Desktop.
Save saghul/1121260 to your computer and use it in GitHub Desktop.
Example Python C extension module
#include "Python.h"
#include "structmember.h"
/* Type definition */
typedef struct {
PyObject_HEAD
PyObject *bar;
PyObject *baz;
} Foo;
static PyTypeObject FooType;
static int
Foo_tp_init(Foo *self, PyObject *args, PyObject *kwargs)
{
const char *c_bar, *c_baz = NULL;
static char *kwlist[] = {"bar", "baz", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:__init__", kwlist, &c_bar, &c_baz)) {
return -1;
}
if (c_bar) {
PyObject *bar = PyString_FromString(c_bar);
Py_XINCREF(bar);
self->bar = bar;
}
if (c_baz) {
PyObject *baz = PyString_FromString(c_baz);
Py_XINCREF(baz);
self->baz = baz;
}
return 0;
}
static PyObject *
Foo_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
Foo *self = (Foo *)FooType.tp_new(type, args, kwargs);
if (!self) {
return NULL;
}
return (PyObject *)self;
}
static int
Foo_tp_clear(Foo *self)
{
Py_CLEAR(self->bar);
Py_CLEAR(self->baz);
return 0;
}
static int
Foo_tp_traverse(Foo *self, visitproc visit, void *arg)
{
Py_VISIT(self->bar);
Py_VISIT(self->baz);
return 0;
}
static void
Foo_tp_dealloc(Foo *self)
{
Foo_tp_clear(self);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyMemberDef Foo_members[] = {
{"bar", T_OBJECT_EX, offsetof(Foo, bar), 0, "Bar attribute"},
{"baz", T_OBJECT_EX, offsetof(Foo, baz), 0, "Baz attribute"},
{NULL}
};
static PyTypeObject FooType = {
PyVarObject_HEAD_INIT(NULL, 0)
"foo.Foo", /*tp_name*/
sizeof(Foo), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)Foo_tp_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
0, /*tp_doc*/
(traverseproc)Foo_tp_traverse, /*tp_traverse*/
(inquiry)Foo_tp_clear, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
Foo_members, /*tp_members*/
0, /*tp_getsets*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
(initproc)Foo_tp_init, /*tp_init*/
0, /*tp_alloc*/
Foo_tp_new, /*tp_new*/
};
/* Add a type to a module */
int
PyModule_AddType(PyObject *module, const char *name, PyTypeObject *type)
{
if (PyType_Ready(type)) {
return -1;
}
Py_INCREF(type);
if (PyModule_AddObject(module, name, (PyObject *)type)) {
Py_DECREF(type);
return -1;
}
return 0;
}
/* Module */
PyMODINIT_FUNC
initfoo(void)
{
PyObject *foo = Py_InitModule("foo", NULL);
FooType.tp_new = PyType_GenericNew;
PyModule_AddType(foo, "Foo", &FooType);
}
@pilotniq
Copy link

Isn't Foo_tp_new(...) calling itself in an infinite recursion?

@cfra
Copy link

cfra commented Jun 4, 2019

Will the tp_clear and the tp_traverse function ever be executed if you don't mark the type with the flag Py_TPFLAGS_HAVE_GC?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment