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
).
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;
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