Home > database >  Adding subclass inheritance outside a class when instantiating
Adding subclass inheritance outside a class when instantiating

Time:07-06

I want to add the inheritance of one or more classes to another class depending on specific requirements; rather than creating multiple subclasses by hand, I want to be able to custom build them on the fly.

For example, the primary class, that would inherit from the others, is Sandwich:

class Sandwich(object):
    def __init__(self):
        super(Sandwich, self).__init__()
        self.bread = "brown"
        self.amount = 2

The base classes would be:

class Meat(object):
    def __init__(self):
        super(Meat, self).__init__()
        self.ham = False
        self.chicken = False
        self.beef = False

class Vegetables(object):
    def __init__(self):
        super(Vegetables, self).__init__()
        self.lettuce = False
        self.onion = False

class Vegan(Vegetables):
    def __init__(self, *args, **kwargs):
        super(Vegetables, self).__init__(*args, **kwargs)
        self.vegan_cheese = False

I want to create instances of these classes like this:

meat_sandwich = Sandwich(Meat)
veg_sandwich = Sandwich(Vegetables)
meat_and_veg_sandwich = Sandwich(Meat, Vegetables)
vegan_sandwich = Sandwich(Vegan)

I want to be able to access all variables and methods from these classes, and from the main class.

print(meat_sandwich.bread)
meat_sandwich.ham = True

I have found that you can assign a new class using __new__, however I have only succeeded in replacing the main class, and not setting up multiple inheritance / subclassing:

    def __new__(cls, *args, **kwargs):
        """ Set to assign any given subclass """
        subcls = [i for i in args if isinstance(i, type)]

        if subcls:
            return super(Sandwich, cls).__new__(*subcls)

        else:
            return superSandwich, cls).__new__(cls)

CodePudding user response:

Instead of using inheritance in my opinion it makes more sense to use composition here.

This will simplify the construction of the objects, and make it more flexible to change (such as adding new ingredients).

For example, each set of ingredient types could be a separate Enum:

from enum import Enum

class Bread(Enum):
    WHITE = "white"
    WHOLE_WHEAT = "whole wheat"
    BROWN = "brown"

class Meat(Enum):
    HAM = "ham"
    CHICKEN = "chicken"
    BEEF = "beef"

class Vegetable(Enum):
    LETTUCE = "lettuce"
    ONION = "onion"

class Vegan(Enum):
    CHEESE = "vegan_cheese"

Now when defining the sandwich class you could do something like this:

class Sandwich:
    def __init__(self, bread, ingredients=None):
        self.bread = bread
        self.ingredients = ingredients or []

To ask something like (as done in your example) if the sandwich contains ham, you could do:

>>> meat_sandwich = Sandwich(Bread.WHITE, [Meat.HAM])
>>> Meat.HAM in meat_sandwich.ingredients
True

To ask if the sandwich contains no meat, you could do:

>>> veg_sandwich = Sandwich(Bread.BROWN, [Vegetable.LETTUCE])
>>> all(not isinstance(i, Meat) for i in veg_sandwich.ingredients)
True

CodePudding user response:

I've managed to get the results I was after, although I appreciate that I did not explain the problem very well, and suspect this might be something of a hack.

At any rate, I hope this helps illustrate what it was I was trying to achieve, and I would be interested in hearing alternate approaches to this solution.

meat_sandwich = type('meatSandwich_type', (Sandwich, Meat), dict())()
veg_sandwich = type('vegSandwich_type', (Sandwich, Vegetables), dict())()
meat_and_veg_sandwich = type('meatAndVegSandwich_type', (Sandwich, Meat, Vegetables), dict())()
vegan_sandwich = type('meatAndVegSandwich_type', (Sandwich, Vegan), dict())()
  • Related