4

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.

1
  • 1
    Please include links to the documentation and also add relevant fragments from it to your question. Commented Nov 14, 2016 at 17:06

2 Answers 2

1

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 type object).

Sign up to request clarification or add additional context in comments.

11 Comments

If I do that, I can still set tp_methods to point to some C implementations, right?
@tbodt: No. You get basically none of the power of the C API. You might as well write the class in Python and have the methods delegate to C functions in their implementations: def some_method(self): return some_c_function(self).
Is there any way to do that without any Python code?
@tbodt: You could probably construct 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.
argh. does anything bad happen if you try to set tp_methods? would setting tp_bases do any good?
|
1

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.