简体   繁体   中英

Overriding python method to return object of correct class with extended data

Suppose I have a python class like:

class Meal(object):
   def __init__(self, starter, main="steak"):
       self.starter = starter
       self.main = main

   def new_meal_eaten_starter(self):
       return Meal("Eaten-%s" % self.starter, main=self.main)

   def __repr__(self):
       return "%s %s" % (self.starter, self.main)

Now I want to inherit from this class, adding some data:

class MealWithDessert(Meal):
    def __init__(self, dessert, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.dessert = dessert

    def __repr__(self):
        return "%s %s %s" % (self.starter, self.main, self.dessert)

Of course this happens:

>>> x = MealWithDessert("cake", "salad", "pizza")
salad pizza cake
>>> x.new_meal_eaten_starter()
eaten-salad pizza

Of course what I want to see was eaten-salad pizza cake. I can solve this problem by overriding the method to use the base method:

    def new_meal_eaten_starter(self):
        new_meal_no_dessert = super().new_eaten_starter()
        new_meal = MealWithDessert(self.dessert, new_meal_no_dessert.starter, main=new_meal_no_dessert.main)

    return new_meal

... but that is dammn ugly. Or by basically copying the base method (which violates DRY):

def new_meal_eaten_starter(self):
      return MealWithDessert(self.dessert, "Eaten-%s" % self.starter, main=self.main)

... and for more complex functions both options are really horrific. Surely there must be a better way?

The snippet below achieved what you intend to do, I hope it helps

class Meal(object):
    def __init__(self, starter, main="steak"):
            self.starter = starter
            self.main = main

    def new_meal_same_starter(self, new_main):
        meal_class = globals()[self.__class__.__name__]
        new_args = self.__dict__.copy()
        new_args['starter'] = "Eaten-%s" % new_args['starter']
        new_args['main'] = new_main
        return meal_class(**new_args)

    def __repr__(self):
        return "%s %s" % (self.starter, self.main)



class MealWithDessert(Meal):
    def __init__(self, dessert, *args, **kwargs):
            super(MealWithDessert, self).__init__(*args, **kwargs)
            self.dessert = dessert

    def __repr__(self):
        return "%s %s %s" % (self.starter, self.main, self.dessert)


x = MealWithDessert("cake", "salad", "pizza")
print(x)
y = x.new_meal_same_starter("tofu")

a = Meal("Rice")
b = a.new_meal_same_starter("Bread")

print(a)
print(b)

print(y)

print(x)

I think problem here is following method in class meal

   def new_meal_same_starter(self, new_main):
       return Meal(self.starter, main=new_main)

You just need to update the main with new_main meal. So Try this:

   def new_meal_same_starter(self, new_main):
       self.main=new_main

If you need to return from the method, then override it:

   def new_meal_same_starter(self, new_main):
      return MealWithDessert(self.dessert, self.starter, main=new_main)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM