首页 > 解决方案 > 覆盖python方法以返回具有扩展数据的正确类的对象

问题描述

假设我有一个 python 类,如:

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)

现在我想从这个类继承,添加一些数据:

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)

当然会发生这种情况:

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

当然我想看的是吃沙拉披萨蛋糕。我可以通过覆盖使用基本方法的方法来解决这个问题:

    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

……但这太丑了。或者通过基本上复制基本方法(违反 DRY):

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

...对于更复杂的功能,这两种选择都非常可怕。肯定有更好的方法吗?

标签: pythoninheritancemethodsoverriding

解决方案


下面的代码片段实现了您打算做的事情,希望对您有所帮助

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)

推荐阅读