Hurlu' Hurlu' - 1 month ago 12
Python Question

Can a Python class not inherit from multiple classes, but have a "choice" of inheritance?

I'm currently working with a 3Rd party app. This 3rd party app has thoses class defined :

class VeryBaseClass(object):
def __init__():
pass

class BaseClass(VeryBaseClass):
def specific_method():
pass


And then, looots of theses:

class Componenent[1,2,3,4....129883](BaseClass):
def other_specific_method():
pass


I can't modify any of these classes . So , for me to override/supplement methods here, I just have to create a class that inherits from Component, where I can change the methods effortlessly.

The problem is, making MyComponent1, then MyComponent2, MyComponent3, etc... all for copy-pasting the exact same code in the content of the class and just changing the inheritance is very annoying, and not DRY at all!

So, is there a way to create, for example , this class:

class MyComponentGeneric(Component1, Component2, Component3....):
pass


Where MyComponentGeneric would not inherit from EVERY class listed, but could inherit from one OR another, depending of my declaration of the instance ?

Thanks!

Edit with more concrete code :

Actually, I've tried things that belonged in every answer, but I always end up facing the same error :

I made a Factory as Chepney advised :

# This method is the one I use as a replacement
def newrender(self, name, value, attrs=None):
result = super().render(name, value, attrs)
if self.image is None:
return result
else:
return '<img class="form-image" height="100" width="100" src="{}"/>'.format(self.image.url) + result


def MyWidgetFactory(widget, picture):
newclass = type("WithImage" + widget.__name__, (widget,), dict(render=newrender))
newclass.image = image
return newclass()


But as soon as my newrender method launches, I get this error :

result = super().render(name, value, attrs)
RuntimeError: super(): __class__ cell not found


Is it because of a bad usage of the factory or something else ?

5 minutes later edit
Okay, I just had to populate the super cell by calling it with super(type(self), self). Not quite sure how it works but, heh, it worked!

Thanks everyone !

Answer

This is a use case for a dictionary (or possibly a list, if the dictionary keys are just a sequence of consecutive integers):

base_classes = {
    1: Component1,
    2: Component2,
    # ...
}

def ComponentFactory(comp_type):
    return base_classes(comp_type)()

Here, ComponentFactory creates the instance for you, rather than creating a new class that essentially would just wrap an existing class without actually adding to it.


If you really need a new type, you can create that in the factory as well:

def ComponentFactory(comp_type):
    new_type = type('SomeTypeName', (base_classes[comp_type],), {})
    return new_type()

However, you should probably take care that you only create one such wrapper per real class, so that you don't end up with a bunch of identical singleton classes.

Comments