0

The newtypes tutorial shows you how to inherit from a base python class. Can you inherit from your own python class? Something like this?

  PyObject *mod = PyImport_AddModule("foomod");
  PyObject *o = PyObject_GetAttrString(mod, "BaseClass");
  PyTypeObject *t = o->ob_type;
  FooType.tp_base = t;
  if (PyType_Ready(&FooType  ) < 0) return NULL;

though you need to define your struct with the base class as the first member per the documentation so it sounds like this is not possible? ie how would I setup the Foo struct?

typedef struct {
    PyListObject list;
    int state;
} SubListObject;

What I'm really trying to do is subclass _UnixSelectorEventLoop and it seems like my only solution is to define a python class that derives from my C class and from _UnixSelectorEventLoop with my C class listed first so that it can override methods in the other base class.

DavidW
  • 29,336
  • 6
  • 55
  • 86
Craftables
  • 236
  • 1
  • 8
  • I've updated the link to the documentation, rather than the github source that generates the documentation, because some code snippets are included from other files on the github source so it's quite hard to read – DavidW Nov 27 '19 at 16:41

1 Answers1

0

I think you're basically right on your assessment:

it seems like my only solution is to define a python class that derives from my C class and from _UnixSelectorEventLoop with my C class listed first so that it can override methods in the other base class.

You can't define a class that inherits from a Python class because it'd need to start with a C struct of basically arbitrary size.

There's a couple of other options that you might like to consider:

  1. You could create a class the manual way by calling PyType_Type. See this useful answer on a question about multiple inheritance which is another sort of inheritance that the C API struggles with. This probably limits you too much, since you can't have C attributes, but you can have C functions.

  2. You could do "inheritance by composition" - i.e. have you _UnixSelectorEventLoop as part of the object, then forward __getattr__ and __setattr__ to it in the event of unknown attributes. It's probably easier to see what I mean with Python code (which is simply but tediously transformed into C API code)

    class YourClass:
        def __init__(self,...):
            self.state = 0
            self._usel = _UnixSelectorEventLoop()
        def __getattr__(self, name):
            return getattr(self._usel, 'name')
        def __setattr__(self, name, value):
            if name in self.__dict__:
                object.__setattr__(self, name, value)
            else:
                setattr(self._usel, name, value)
        # maybe __hasattr__ and __delattr__ too?
    

    I'm hoping to avoid having to write this C API code myself, but the slots are tp_getattro and tp_setattro. Note that __getattr__ will need to be more comprehensive in the C version, since it acts closer to the __getattribute__ in Python. The flipside is that isinstance and issubclass will fail, which may or may not be an issue for you.

DavidW
  • 29,336
  • 6
  • 55
  • 86