How do I create a type using the Python C API that inherits from multiple other types?
The Python documentation includes an example of a type that inherits from one other type, but there is no example or mention of multiple inheritance I could find.
How do I create a type using the Python C API that inherits from multiple other types?
The Python documentation includes an example of a type that inherits from one other type, but there is no example or mention of multiple inheritance I could find.
The C API does not support multiple inheritance. You'd have to call PyType_Type yourself, simulating a standard Python class statement. This is documented under the C API section on specifying a base type for an extension type:
PyTypeObject* PyTypeObject.tp_base
An optional pointer to a base type from which type properties are inherited. At this level, only single inheritance is supported; multiple inheritance require dynamically creating a type object by calling the metatype.
This field is not inherited by subtypes (obviously), but it defaults to
&PyBaseObject_Type(which to Python programmers is known as the typeobject).
tp_methods to point to some C implementations, right?def some_method(self): return some_c_function(self).PyCFunction objects yourself with PyCFunction_New and insert them into the dict you pass to PyType_Type. I think that'd work. You'd be getting into undocumented territory if you do it.tp_methods? would setting tp_bases do any good?Let's say you have a module named test, with the following classes:
class A:
a = 1
class B:
b = 2
And the idea is to create a new class C which inherits from A and B:
import test
class C(test.A, test.B):
pass
The specification on PyTypeObject.tp_base says that it does not support multiple bases classes and that you have to create the class "by calling the metatype". In this case, the metatype is type, so the class can be created this way:
from test import A, B
C = type("C", (A, B), {})
Translating that to C is straightforward, although a bit verbose:
// from test import A, B
PyObject* test_module = PyImport_ImportModuleNoBlock("test");
if (test_module == NULL) return NULL;
PyObject* ClassA = PyObject_GetAttrString(test_module, "A");
if (ClassA == NULL) return NULL;
PyObject* ClassB = PyObject_GetAttrString(test_module, "B");
if (ClassB == NULL) return NULL;
// name, bases, classdict = "C", (A, B), {}
PyObject *name = PyUnicode_FromString("C");
if (name == NULL) return NULL;
PyObject *bases = PyTuple_Pack(2, ClassA, ClassB);
if (bases == NULL) return NULL;
PyObject *classdict = PyDict_New();
if (dict == NULL) return NULL;
// C = type(name, bases, classdict)
PyObject *ClassC = PyObject_CallObject(
(PyObject*)&PyType_Type, PyTuple_Pack(3, name, bases, classdict));
if (ClassC == NULL) return NULL;
if (PyModule_AddObject(m, "C", ClassC)) return NULL;