Skip to content
Advertisement

Create subclass from superclass initializer in Python

Suppose I have a class Fruit and two Subclasses of it Orange(Fruit) and Banana(fruit)

Fruit has an initializer, and I pass some parameters to it. But I don’t want it to just create and return a fruit necessarily, but based upon the parameters passed to it, to possibly return one of several different subclasses of it. For example:

Fruit(color="yellow") might return a Banana object whereas Fruit(color="orange") would return an Orange.

How can I do this? I can’t do it in __init__ because the class has already been created. I tried doing it in __new__ but this wound up messy because my could would create the subclass (as expected), but would then wind-up recursivley calling the Superclass’s __new__.

My workaround has been to just define a Fruit.create() static method which creates the appropriate subclass, but this seems a little un-Pythonic.

Is there a “correct” way to do this?

Advertisement

Answer

My point of view is the same as Chris Doyle.

You can use factory mode or your Fruit.create(), I think they are very good

If you want to use your ideas, you can do so

class Meta(type):
    def __call__(cls, *args, **kwargs):
        if cls is Fruit:
            color = kwargs.pop('color', None)
            if color is None:
                raise ValueError("missing keyword argument `color`")
            match color:
                case 'yellow':
                    return Banana()
                case 'orange':
                    return Orange()
                case _:
                    raise ValueError("invalid color: %s" % color)

        return super().__call__(*args, **kwargs)


class Fruit(metaclass=Meta):
    def __init__(self, *, color=None):  # noqa
        pass


class Banana(Fruit):
    pass


class Orange(Fruit):
    pass


if __name__ == '__main__':
    print(Fruit(color='yellow'))
    print(Fruit(color='orange'))
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement